Paddle

Connect Paddle Billing so transactions, refunds, and subscriptions become RefRef facts, and apply discounts and free plan upgrades in Paddle.

The Paddle integration works in two directions:

  • Facts in. Completed transactions, approved refunds and chargebacks, and subscriptions become purchase Events, purchase adjustments, and Subscription facts in your Project. Your server does not send them to the RefRef API.
  • Rewards out. RefRef applies a Program's discount to the customer's Paddle subscription, and delivers its custom Rewards as a free plan upgrade. Paddle has no account credit that RefRef can apply, so account credit Rewards go through your product or are recorded by hand.

You connect one Paddle account to each Project. The Paddle sandbox and live Paddle are separate environments with separate keys: a Sandbox Project connects a sandbox key (pdl_sdbx_apikey_…), and a Live Project connects a live key (pdl_live_apikey_…). Start in the Sandbox Project.

Connect Paddle

  1. In Paddle, open Developer tools → Authentication and create an API key with these permissions: read Products, Prices, Customers, Transactions, and Notifications; read and write Subscriptions and Discounts. Prices read access is needed for plan upgrades.

  2. In RefRef, open the Project's Settings → Integrations, choose Paddle, paste the key, and select Connect. RefRef checks the key with Paddle and stores it encrypted. A key of the other environment is refused. Your Paddle account needs at least one product: RefRef uses your oldest product to recognize the account.

    Connect Paddle in the Integrations settings of a Sandbox Project

  3. The connection shows its webhook URL, which ends in /integrations/v1/paddle/webhooks/<connectionId>. Copy it.

  4. In Paddle, open Developer tools → Notifications and add a destination of type URL with that URL and API version 1. Subscribe it to these events:

    Paddle eventWhat RefRef records
    transaction.completedA purchase Event. A subscription transaction is an invoice; a one-time transaction is an order.
    adjustment.created, adjustment.updatedA refund purchase adjustment for an approved refund, and a dispute_loss adjustment for a chargeback
    subscription.created, subscription.activated, subscription.trialing, subscription.updated, subscription.past_dueThe start of the Subscription
    subscription.paused, subscription.resumedA pause and a resume
    subscription.canceledThe end of the Subscription
  5. Copy the destination's secret key (pdl_ntfset_…), paste it into the connection's Signing secret field in RefRef, and select Save. Until you save it, RefRef refuses the destination's events.

    The webhook URL and the signing secret of a Paddle connection

RefRef checks the Paddle-Signature of each event and refuses a changed body, a timestamp more than five minutes old, or another secret. A repeated event is stored once.

Name the customer at checkout

RefRef never matches a Paddle customer by email. Your app names the participant in the checkout's custom data:

Custom data keyValue
refref_external_idThe participant's externalId in the Project, for example your user ID. Required.
refref_participant_kindindividual (the default) or group, for a team account. Another value names nobody.
refref_handleOptional. The value of the buyer's refref_handle cookie, from the landing script. See Buyers who did not sign up first.

With Paddle.js, pass the keys as customData when you open the checkout. Your server can also create the transaction with custom_data and open the checkout for its ID:

Open a Paddle.js checkout
Paddle.Checkout.open({
  items: [{ priceId: "pri_…", quantity: 1 }],
  customData: {
    refref_external_id: user.id,
    // Optional: the buyer's browser, for a buyer who did not sign up first.
    refref_handle: readCookie("refref_handle"),
  },
});

Paddle copies the checkout's custom data to the subscription and to each of its later transactions, so renewals name the same participant. The custom data of the customer does not count. A transaction without refref_external_id gives no fact.

Buyers who did not sign up first

A buyer who clicked a referral link and then paid, with no earlier signup, has no identified browser yet. Read the buyer's refref_handle cookie and put its value into the same custom data as refref_handle, next to refref_external_id. At the participant's first fact, RefRef identifies that browser to the participant, so the referral click counts.

  • RefRef uses the handle only when the participant has no Event yet, and only when the handle is open and belongs to the Project. A handle that a signup already identified changes nothing.
  • The first fact is the moment of identification: the start of the subscription, or the one-time payment. A click counts when it is at most 90 days before it.
  • A buyer without the cookie, or a checkout without refref_handle, is attributed only through a referral the participant already has.

Paddle.js custom data comes from the page, so the buyer can change it. The landing script's cookie is readable by the page; a buyer can name only a handle that they hold.

What RefRef does with the facts

  • First purchase. A billing fact carries no browser data. The start of the subscription uses the referral that the participant already has, for example from a signup that identified the browser. When the participant has no referral yet and purchase is a qualifying event type, the fact can create one from a click in a browser that your backend identified to the participant before, or that the checkout named with refref_handle. Its transactions get the referral as their attribution.
  • Renewals. Each later transaction of the subscription inherits the subscription's referral without a new click, also after the attribution window. A Program rule that pays on each purchase earns a Reward on each completed transaction.
  • Paid history. Before RefRef evaluates a purchase Reward, it reads the referee's completed transactions between the referral and the purchase, so that a "first purchase" rule counts only a first purchase.
  • Refunds and chargebacks. Paddle approves a refund before it takes effect; RefRef records it when Paddle approves it. An approved refund reduces the purchase by its amount, tax excluded, and a chargeback removes the whole purchase. Rewards calculated from that purchase get a matching adjustment. When the purchase is fully refunded, RefRef takes back a Reward that it already delivered: it removes the discount. A partial refund leaves a delivered Reward in place.
  • Missed events. Every five minutes RefRef reads Paddle's event list (Paddle keeps events for 90 days) and records any fact that a webhook did not bring.

Deliver Rewards in Paddle

In the Program's settings, open Delivery and choose Give a discount in Paddle:

The Delivery settings of a Program connected to Paddle

RewardDelivery in Paddle
DiscountA percentage discount that RefRef applies to the customer's active or trialing subscription from its next billing period, for the rule's duration: one billing period, the rule's months in billing periods of the subscription (rounded up, so a yearly plan gets one year for 3 months), or every period. A subscription billed by day or week cannot take a discount of months. A void removes it from the subscription.
Account creditNot available in Paddle. Choose Through your product (webhook) or Record by hand.
CustomA free upgrade to a higher plan for a number of billing periods. See Give a free plan upgrade.

The discount cannot be used at checkout: RefRef applies it to the subscription itself. A delivery stops, with a reason in the Console, when the customer has no active subscription or more than one, or when the subscription already has another discount (RefRef does not replace it). Paddle locks a subscription for changes shortly before a renewal; RefRef tries again later.

RefRef delivers to the Paddle customer of the beneficiary. It learns the customer from the beneficiary's own transactions and subscriptions; for a referrer who has not paid through Paddle, send the Paddle customer ID (ctm_…) as billingIds.paddle with PUT /v1/participants. A delivery is Paddle's success answer.

Not available: account credit, and payouts to referrers through Paddle.

Give a free plan upgrade

A custom Reward can move the customer to a higher plan for a number of billing periods. The customer keeps paying the price of the current plan, and then goes back to it automatically.

Set it up

  1. In the Project's Settings → Custom units, add a unit for the upgrade, for example "Pro month".
  2. In the Program's rules, give that unit as a custom Reward with a quantity of 1. A plan upgrade refuses another quantity.
  3. In the Program's Delivery settings, choose Upgrade the plan in Paddle for custom Rewards. Under Plan upgrades, enter for the unit the Paddle price ID (pri_…) of the higher plan and the number of billing periods, from 1 to 12. A unit without a plan goes through your product (webhook).

The plan upgrade settings of a Program connected to Paddle

What the customer gets

  1. At once, RefRef switches the customer's subscription to the higher price, with no charge. The rest of the current billing period on the higher plan is free.
  2. RefRef applies a flat discount of the price difference to the next N renewals, so each of them bills the customer's current price.
  3. Paddle locks a subscription 30 minutes before a renewal, so RefRef switches back one hour before renewal N+1: it sets the current price again, with no charge, and removes the discount. Renewal N+1 bills the current plan.

If RefRef cannot switch back before Paddle's lock, renewal N+1 bills the higher price in full, and RefRef switches back after it. Check such a renewal in Paddle. A scheduled cancel does not stop the switch back. If the customer changed the plan or the subscription ended, RefRef records this at the switch back and changes nothing.

When RefRef does not upgrade

RefRef changes nothing, and the Reward waits for you with the reason, when:

  • The customer has no active subscription (a trialing, past-due, or paused subscription does not count), or has more than one.
  • The subscription already has a discount.
  • The price that you set is the current price, or it is not higher.
  • The two prices have a different currency, billing cycle, or tax mode.

The delivery also fails, for you to resolve, when the subscription has more than one item or a quantity other than 1, when it already has a scheduled change, or when a price has country price overrides.

A void before the switch back switches the subscription back to the current price at once, with no charge.

A connection made before plan upgrades

A Paddle connection made before plan upgrades were available does not offer Upgrade the plan in Paddle. In Settings → Integrations, select Test connection on the Paddle connection. After the test passes, the option is available.

Test the integration

  1. Connect a sandbox key to your Sandbox Project and add the notification destination in the Paddle sandbox.
  2. Create a referral link for a participant. Open it in a browser on a page with the landing script, and sign up there, so that your backend identifies the browser with the signup.
  3. Open a Paddle.js checkout with the custom data (call Paddle.Environment.set("sandbox") first) and pay it with Paddle's test card 4242 4242 4242 4242, CVC 100.
  4. In the Sandbox Project, check Referrals and Rewards. A discount that RefRef delivered shows its Paddle discount ID, and the subscription in Paddle shows the discount.
  5. Refund part of the transaction in Paddle. After Paddle approves the refund, check the adjustment on the Reward.

Paddle can move a subscription's next billing date only 30 minutes or more ahead, so a test renewal takes at least half an hour.

On this page