Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paddle Billing Docs #873

Merged
merged 8 commits into from
Oct 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,18 @@

Follow this guide to upgrade older Pay versions. These may require database migrations and code changes.

## **Pay 6.0 to Unreleased**

This version adds support for Paddle's new Billing APIs and renames the existing Paddle implementation to Paddle Classic.

If you were using Paddle before, you'll need to update existing Paddle customers to `paddle_classic`.

```ruby
Pay::Customer.where(processor: :paddle).update_all(processor: :paddle_classic)
```

You'll also need to update the Webhook endpoint from `/pay/webhooks/paddle` to `/pay/webhooks/paddle_classic`

## **Pay 5.0 to 6.0**
This version adds support for accessing the start and end of the current billing period of a subscription. This currently only works with Stripe subscriptions.

Expand Down
3 changes: 3 additions & 0 deletions docs/1_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ gem "stripe", "~> 9.0"
gem "braintree", "~> 4.7"

# To use Paddle, also include:
gem "paddle", "~> 2.1"

# To use Paddle Classic, also include:
gem "paddle_pay", "~> 0.2"

# To use Receipts gem for creating invoice and receipt PDFs, also include:
Expand Down
9 changes: 9 additions & 0 deletions docs/2_configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ braintree:
public_key: yyyy
merchant_id: aaaa
environment: sandbox
paddle:
seller_id: 1111
api_key: yyyy
signing_secret: pdl_ntfset...
environment: sandbox
paddle_classic:
vendor_id: xxxx
vendor_auth_code: yyyy
Expand Down Expand Up @@ -55,6 +60,10 @@ Pay will also check environment variables for API keys:
* `BRAINTREE_PUBLIC_KEY`
* `BRAINTREE_PRIVATE_KEY`
* `BRAINTREE_ENVIRONMENT`
* `PADDLE_SELLER_ID`
* `PADDLE_API_KEY`
* `PADDLE_SIGNING_SECRET`
* `PADDLE_ENVIRONMENT`
* `PADDLE_CLASSIC_VENDOR_ID`
* `PADDLE_CLASSIC_VENDOR_AUTH_CODE`
* `PADDLE_CLASSIC_PUBLIC_KEY`
Expand Down
5 changes: 3 additions & 2 deletions docs/3_customers.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ Before you can process payments, you need to assign a payment processor for the
@user.set_payment_processor :stripe
@user.set_payment_processor :braintree
@user.set_payment_processor :paddle
@user.set_payment_processor :paddle_classic
@user.set_payment_processor :fake_processor, allow_fake: true
```

Expand Down Expand Up @@ -56,9 +57,9 @@ If you need to access the API object directly from the payment processor like th
#=> #<Stripe::Customer>
```

##### Paddle:
##### Paddle Classic:

It is currently not possible to retrieve a Customer object through the Paddle API.
It is currently not possible to retrieve a Customer object through the Paddle Classic API.

## Next

Expand Down
27 changes: 27 additions & 0 deletions docs/4_payment_methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,33 @@ This will add the payment method via the API and mark it as the default for futu

##### Paddle

For updating payment method details on Paddle, a transaction ID is required. This can be generated by using

```ruby
subscription = @user.payment_processor.subscription(name: "plan name")
transaction = subscription.payment_method_transaction
```

Once you have a transaction ID, you can then pass that through to Paddle.js like so

```html
<a href="#"
class="paddle_button"
data-display-mode="overlay"
data-theme="light"
data-locale="en"
data-transaction-id="<%= transaction.id %>"
>
Update Payment Details
</a>
```

This will then open the Paddle overlay and allow the user to update their payment details.

For more information, [see the Paddle documentation](https://developer.paddle.com/build/subscriptions/update-payment-details)

##### Paddle Classic

Paddle uses an [Update Payment Details URL](https://developer.paddle.com/guides/how-tos/subscriptions/update-payment-details) for each customer which allows them to update the payment method. This is stored on the `Pay::Subscription` record for easy access.

```ruby
Expand Down
16 changes: 13 additions & 3 deletions docs/5_charges.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ You may pass optional arguments that will be directly passed on to the payment p

On failure, a `Pay::Error` will be raised with details about the payment failure.

##### Paddle Charges
##### Paddle Classic Charges

Paddle requires an active subscription on the customer in order to create a one-time charge. It also requires a `charge_name` for the charge.
Paddle Classic requires an active subscription on the customer in order to create a one-time charge. It also requires a `charge_name` for the charge.

```ruby
@user.payment_processor.charge(1500, {charge_name: "Test"}) # $15.00 USD
Expand Down Expand Up @@ -74,13 +74,23 @@ The details saved will vary depending upon the payment method used.

## Receipt URL

Paddle and Stripe provide a receipt URL for each payment.
Paddle Classic and Stripe provide a receipt URL for each payment.

```ruby
@charge.paddle_receipt_url
@charge.stripe_receipt_url
```

## Paddle Receipts

Paddle Billing doesn't provide a receipt URL like Paddle Classic did.

In order to retrieve a PDF invoice for a transaction, an API request is required. This will return a URL to the PDF invoice. This URL is not permanent and will expire after a short period of time.

```ruby
Paddle::Transaction.invoice(id: @charge.processor_id)
```

## Next

See [Subscriptions](6_subscriptions.md)
2 changes: 1 addition & 1 deletion docs/6_subscriptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ You can set this to another option as shown below.
@user.payment_processor.subscription.pause(behavior: "mark_uncollectible", resumes_at: 1.month.from_now)
```

##### Pause a Paddle Subscription
##### Pause a Paddle Classic Subscription

Paddle will pause payments at the end of the period. The status remains `active` until the period ends with a `paused_from` value to denote when the subscription pause will take effect. When the status becomes `paused` the subscription is no longer active.

Expand Down
4 changes: 3 additions & 1 deletion docs/7_webhooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ To configure webhooks on your payment processor, use the following URLs (with yo
* **Stripe** - `https://example.org/pay/webhooks/stripe`
* **Braintree** - `https://example.org/pay/webhooks/braintree`
* **Paddle** - `https://example.org/pay/webhooks/paddle`
* **Paddle Classic** - `https://example.org/pay/webhooks/paddle_classic`

#### Mount path

Expand Down Expand Up @@ -50,7 +51,8 @@ Since we support multiple payment providers, each event type is prefixed with th
```ruby
"stripe.charge.succeeded"
"braintree.subscription_charged_successfully"
"paddle.subscription_created"
"paddle.subscription.created"
"paddle_classic.subscription_created"
```

## Custom Webhook Listeners
Expand Down
71 changes: 40 additions & 31 deletions docs/paddle/1_overview.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,61 @@
# Using Pay with Paddle

Paddle works differently than most of the other payment processors so it comes with some limitations and differences.
Paddle Billing is Paddle's new subscription billing platform. It differs quite a bit
from Paddle Classic. This guide will help you get started with implementing it in your
Rails application.

* You cannot create a Customer from the API
* Checkout only happens via iFrame or hosted page
* Cancelling a subscription cannot be resumed
* Payment methods can only be updated while a subscription is active
* Paddle customers are not reused when a user re-subscribes

## Paddle Sandbox
## Creating Customers

The [Paddle Sandbox](https://developer.paddle.com/getting-started/sandbox) can be used for testing your Paddle integration.
Paddle now works similar to Stripe. You create a customer, which subscriptions belong to.

```html
<script src="https://cdn.paddle.com/paddle/paddle.js"></script>
<script type="text/javascript">
Paddle.Environment.set('sandbox');
Paddle.Setup({ vendor: <%= Pay::Paddle.vendor_id %> });
</script>
```ruby
# Set the payment processor
@user.set_payment_processor :paddle

# Create the customer on Paddle
@user.payment_processor.customer
```
## Paddle Public Key

Paddle uses public/private keys for webhook verification. You can find
your public key [here for Production](https://vendors.paddle.com/public-key)
and [here for Sandbox](https://sandbox-vendors.paddle.com/public-key).
## Prices & Plans

There are 3 ways that you can set the public key in Pay.
Paddle introduced Products & Prices to support more payment options. Previously,
they Products and Plans separated.

In either example, you can set the environment variable or in Rails credentials.
## Subscriptions

### File
Paddle subscriptions are not created through the API, but through Webhooks. When a
subscription is created, Paddle will send a webhook to your application. Pay will
automatically create the subscription for you.

You can download the public key from the link above and save it to a location which your Rails application
can access. Then set the `PADDLE_PUBLIC_KEY_FILE` to the location of the file.
## Configuration

### Key
### Paddle API Key

Set the `PADDLE_PUBLIC_KEY` environment variable with your public key. Replace any spaces with `\n` otherwise
you may get a `OpenSSL::PKey::RSAError` error.
You can generate an API key [here for Production](https://vendors.paddle.com/authentication)
or [here for Sandbox](https://sandbox-vendors.paddle.com/authentication)

### Base64 Encoded Key
### Paddle Environment

Or you can set a Base64 encoded version of the key. To do this, download a copy of your public key
then open a `rails console` and enter the following:
Paddle has two environments: Sandbox and Production. To use the Sandbox environment,
set the Environment value to `sandbox`. By default, this is set to `production`.

```ruby
paddle_public_key = OpenSSL::PKey::RSA.new(File.read("paddle.pem"))
Base64.encode64(paddle_public_key.to_der)
```
### Paddle Signing Secret

Paddle uses a signing secret to verify that webhooks are coming from Paddle. You can find
this after creating a webhook in the Paddle dashboard. You'll find this page
[here for Production](https://vendors.paddle.com/notifications) or
[here for Sandbox](https://sandbox-vendors.paddle.com/notifications).

### Environment Variables

Pay will automatically look for the following environment variables, or the equivalent
Rails credentials:

Copy what's displayed and set the `PADDLE_PUBLIC_KEY_BASE64` environment variable.
- `PADDLE_SELLER_ID`
- `PADDLE_ENVIRONMENT`
- `PADDLE_API_KEY`
- `PADDLE_SIGNING_SECRET`
77 changes: 52 additions & 25 deletions docs/paddle/2_javascript.md
Original file line number Diff line number Diff line change
@@ -1,35 +1,62 @@
# Paddle Javascript

### Update Payment Details
Paddle.js v2 is used for Paddle Billing. It is a Javascript library that allows you to embed
Paddle Checkout into your website.

https://developer.paddle.com/guides/how-tos/subscriptions/update-payment-details

##### Inline
## Setup

```html
<a href="#!" class="paddle_button"
data-override="https://checkout.paddle.com/subscription/update..."
data-success="https://example.com/subscription/update/success"
>Update Payment Information</a>
<script src="https://cdn.paddle.com/paddle/v2/paddle.js"></script>
<script type="text/javascript">
Paddle.Environment.set("sandbox");
Paddle.Setup({
// This can be hard-coded or set using environment variables/Rails credentials
// It needs to be an integer, not a string
seller: <%= Pay::Paddle.seller_id %>
});
</script>
```

```javascript
Paddle.Checkout.open({
override: 'https://checkout.paddle.com/subscription/update...',
success: 'https://example.com/subscription/update/success'
});
```
## Generating a Checkout Button

With Paddle.js initialized, it will automatically look for any elements with the `paddle_button`
class and turn them into a checkout button.

It supports sending HTML Data Attributes to customize the checkout button and session.

You can view the [supported attributes here](https://developer.paddle.com/paddlejs/html-data-attributes).

In this example, the `data-customer-id` attribute is set to the Paddle Customer ID. This is used
to link the newly created subscription to this customer.

##### Overlay

```javascript
Paddle.Checkout.open({
override: 'https://checkout.paddle.com/subscription/update...',
method: 'inline',
frameTarget: 'checkout-container', // The className of your checkout <div>
frameInitialHeight: 416,
frameStyle: 'width:100%; min-width:312px; background-color: transparent; border: none;', // Please ensure the minimum width is kept at or above 312px.
success: 'https://example.com/subscription/update/success'
});
The `data-items` attribute requires an array of items for this checkout. It also requires a
`priceId` and `quantity` for each item.

```html
<a href='#'
class='paddle_button'
data-display-mode='overlay'
data-theme='none'
data-locale='en'
data-items='[
{
"priceId": "<%= plan.price_id %>",
"quantity": 1
}
]'
data-customer-id="<%= @user.payment_processor.processor_id %>"
>
Sign up to <%= plan.name %>
</a>
```

## Overlay Checkout

The overlay checkout is the default checkout method. It will open a modal on top of your website.

## Inline Checkout

Inline checkout can be enabled by setting the `data-display-mode` attribute to `inline`. This allows
you to have tighter integration within your application.

For more information, see the [Paddle documentation](https://developer.paddle.com/build/checkout/build-branded-inline-checkout).
22 changes: 22 additions & 0 deletions docs/paddle/3_webhooks.md
Original file line number Diff line number Diff line change
@@ -1 +1,23 @@
# Paddle Webhooks

## Endpoint

The webhook endpoint for Paddle is `/pay/webhooks/paddle` by default.

## Events

Pay requires the following webhooks to properly sync charges and subscriptions as they happen.

```ruby
subscription.activated
subscription.canceled
subscription.created
subscription.imported
subscription.past_due
subscription.paused
subscription.resumed
subscription.trialing
subscription.updated

transaction.completed
```
16 changes: 16 additions & 0 deletions docs/paddle_classic/3_webhooks.md
Original file line number Diff line number Diff line change
@@ -1 +1,17 @@
# Paddle Classic Webhooks

## Endpoint

The webhook endpoint for Paddle is `/pay/webhooks/paddle_classic` by default.

## Events

Pay requires the following webhooks to properly sync charges and subscriptions as they happen.

```ruby
subscription_created
subscription_updated
subscription_cancelled
subscription_payment_succeeded
subscription_payment_refunded
```
Loading