Billing providers
Connect Stripe, Paddle, Lemon Squeezy, Polar, Chargebee, Shopify, Recurly, Braintree, WooCommerce or BigCommerce so payments, refunds and disputes flow into commissions automatically.
A billing connection gives your billing provider a webhook URL on Referalli. The provider sends its normal webhooks there; Referalli verifies the signature, translates each event into a canonical billing event, and processes commissions. You connect your own provider account; Referalli holds no platform billing keys.
Create a connection
curl -X POST https://referalli.com/v1/billing/connections \
-H "Authorization: Bearer $KEY" \
-H "content-type: application/json" \
-d '{"provider": "stripe", "name": "Stripe live", "webhookSecret": "whsec_from_stripe_dashboard"}'{
"id": "bcon_01JB...",
"provider": "stripe",
"webhookSecret": "whsec_from_stripe_dashboard",
"webhookUrl": "/webhooks/billing/bcon_01JB..."
}provider is one of stripe, paddle, lemonsqueezy, polar, chargebee, shopify, recurly, braintree, woocommerce, bigcommerce or generic. Point the provider at the full URL:
https://referalli.com/webhooks/billing/bcon_01JB...webhookSecret must match what the provider signs with. If you omit it, Referalli generates one (whsec_…) and returns it once; enter that in providers that let you choose the secret (Lemon Squeezy, WooCommerce, BigCommerce, generic).
Set a provider-issued secret
Stripe, Paddle, Polar, Shopify and Recurly issue the signing secret themselves, after you register the webhook URL. Create the connection first, register its URL with the provider, then store the secret the provider shows you:
curl -X PUT https://referalli.com/v1/billing/connections/bcon_01JB.../secret \
-H "Authorization: Bearer $KEY" \
-H "content-type: application/json" \
-d '{"webhookSecret": "whsec_from_stripe_dashboard"}'
# { "id": "bcon_01JB...", "provider": "stripe", "ok": true }webhookSecret is at least 8 characters; for Chargebee it is the username:password pair, and for Braintree the public_key:private_key pair. The call replaces the stored secret, requires the owner or admin role, is audited, and returns 404 for an unknown connection. Until the right secret is stored, the provider's webhooks fail with 401.
Add API credentials (Recurly, BigCommerce)
Recurly's JSON webhooks and BigCommerce's webhooks carry only ids, so Referalli reads each invoice, payment or order from the provider's API with your own credentials. Store them once per connection:
curl -X PUT https://referalli.com/v1/billing/connections/bcon_01JB.../credentials \
-H "Authorization: Bearer $KEY" \
-H "content-type: application/json" \
-d '{"apiKey": "your_recurly_private_api_key", "region": "us"}'
# { "id": "bcon_01JB...", "provider": "recurly", "ok": true }Provider | Fields |
|---|---|
Recurly |
|
BigCommerce |
|
The credentials are stored encrypted, used only to read the objects a webhook names, and never returned. Until they're set, that connection's webhooks get 400, so the provider retries them. GET /v1/billing/connections reports needsCredentials and hasCredentials for each connection. Requires owner or admin; audited.
Match customer ids
Payments are matched to referrals by customer id. Either call associate with the customer id this provider puts in its webhooks (listed below), or link the provider's customer to your own id with referally_customer_ref metadata. See Linking billing customers.
Provider reference
Stripe
Signature:
Stripe-Signatureheader (t=…,v1=…), HMAC-SHA256 of{t}.{body}. Use the endpoint's signing secret from the Stripe dashboard aswebhookSecret.customerRef: the Stripe customer id (
cus_…).Events used:
invoice.paid,customer.created,customer.updated,customer.subscription.created,customer.subscription.updated,customer.subscription.deleted,charge.refunded,charge.dispute.created.Invoice metadata
expansion: "true"marks expansion revenue. A subscription created intrialingstatus records atrialconversion and pays any trial bounty.referally_customer_refin customer, subscription or invoice metadata links thecus_…id to the referral filed under that id.customer.createdandcustomer.updatedare only used for this link.
Paddle
Signature:
Paddle-Signatureheader (ts=…;h1=…), HMAC-SHA256 of{ts}:{body}.customerRef: Paddle
customer_id.Events used:
transaction.completed,subscription.created,subscription.canceled,adjustment.created.A subscription created in
trialingstatus records a trial.referally_customer_refincustom_datalinks the customer.
Lemon Squeezy
Signature:
X-Signatureheader, hex HMAC-SHA256 of the body.customerRef: the
customer_idattribute.Events used:
order_created,subscription_payment_success,subscription_created,subscription_cancelled,subscription_expired,order_refunded,subscription_payment_refunded.Refunds and chargebacks: Lemon Squeezy is the merchant of record and sends no dispute event; a lost chargeback arrives as a refund. A refunded order Lemon Squeezy marks
fraudulentis clawed back in full, like a dispute. Itsrefunded_amountis the running total, so each partial refund only reverses what earlier refunds haven't.A subscription created
on_trialrecords a trial.referally_customer_refin checkout custom data (checkout[custom][referally_customer_ref], delivered asmeta.custom_data) links the customer.
Polar
Signature:
webhook-id,webhook-timestampandwebhook-signatureheaders; the signature isv1,plus the base64 HMAC-SHA256 of{id}.{timestamp}.{body}, keyed with the connection secret as given.customerRef: Polar
customer_id.Events used:
order.created,subscription.created,subscription.canceled,subscription.revoked,refund.created.referally_customer_refin the object'smetadatalinks the customer. Set it as checkout metadata.
Chargebee
Authentication: Chargebee does not sign webhooks. Protect the endpoint with HTTP Basic auth in Chargebee, and set
webhookSecretto the sameusername:passwordpair.customerRef: the Chargebee customer id.
Events used:
payment_succeeded,subscription_created,subscription_cancelled,payment_refunded,dispute_created.Disputes:
dispute_createdclaws back the invoice the disputed payment paid (the transaction'slinked_invoices), in full, like a Stripe dispute. A won dispute doesn't reinstate the commission; correct it through the ledger if you want to.A subscription created
in_trialrecords a trial. Chargebee events carry no custom metadata, so associate customers with the Chargebee customer id.
Shopify
Signature:
X-Shopify-Hmac-Sha256header, base64 HMAC-SHA256 of the body. Use your app's webhook secret.customerRef: the order's customer id, falling back to the customer's email.
Events used: order webhooks (
orders/create,orders/paid) becomeinvoice_paid; refund webhooks (refunds/create) becomerefund.Discount codes on the order are checked against your partner coupons. A match attributes the buyer to that partner at purchase time, with no click needed.
Recurly
Signature:
recurly-signatureheader:<unix ms timestamp>,<hex signature>[,<hex signature>], each an HMAC-SHA256 of{timestamp}.{body}keyed with the endpoint's secret key (two signatures for 24 hours after you regenerate the key). A timestamp more than 5 minutes off is refused. Use JSON webhooks; XML webhooks aren't signed.Credentials: a private API key (above).
customerRef: the account
code. Set it to your own customer id when you create the Recurly account.Events used:
charge_invoice.paidbecomesinvoice_paid,payment.refundedbecomesrefund(against the invoice the original payment paid),subscription.created,subscription.canceledandsubscription.expired.A coupon code on the invoice attributes the buyer to the partner who owns it.
Braintree
Signature: Braintree posts form-encoded
bt_signatureandbt_payload. SetwebhookSecretto your API key pair aspublic_key:private_key; the signature is an HMAC-SHA1 ofbt_payload, keyed with the SHA-1 of the private key.customerRef: the Braintree customer id on the transaction.
Events used:
subscription_charged_successfullybecomesinvoice_paid(the subscription's latest transaction),subscription_went_activebecomessub_created,subscription_canceledandsubscription_expiredbecomesub_canceled,dispute_openedbecomes a full clawback, and a settled credit transaction (transaction_settled) becomes arefund.Braintree sends no webhook for card refunds that settle immediately. Report those as
refundevents through the generic connector.A custom field
referally_customer_refon the transaction links the customer to the id they were referred under.
WooCommerce
Signature:
X-WC-Webhook-Signatureheader, base64 HMAC-SHA256 of the body. Create the webhook under WooCommerce → Settings → Advanced → Webhooks with topic Order updated (and Order created), and set its secret towebhookSecret.customerRef: the WooCommerce customer id, or the billing email for guest checkouts.
Events used: a paid order (status
processingorcompletedwith a payment date) becomesinvoice_paid; each entry in the order'srefundsbecomes its ownrefund.Coupon codes on the order attribute the buyer to the partner who owns the coupon. A
referally_customer_reforder meta field links the buyer to the id they were referred under.
BigCommerce
Authentication: BigCommerce doesn't sign webhooks. Create the webhook with
POST /v3/hooksandheaders: { "X-Referally-Secret": "<webhookSecret>" }; Referalli checks that header.Credentials: a store API token with read access to Orders (above).
customerRef: the BigCommerce customer id, or the billing email for guest orders.
Events used:
store/order/statusUpdatedandstore/order/createdfor an order in a paid state (Awaiting Fulfillment, Awaiting Shipment, Partially Shipped, Shipped or Completed) becomeinvoice_paid;store/order/refund/createdbecomesrefund.Coupon codes on the order attribute the buyer to the partner who owns the coupon.
Generic
For any other system, or your own backend. Event types are invoice_paid, sub_created, sub_updated, sub_canceled, refund, dispute and customer_updated. Send customerRef as the id you attributed the signup under, or set linkedCustomerRef to it. See the generic conversion API.
Responses and errors
A processed webhook returns 200 with { "received": n, "results": [...] }. Events of types Referalli does not use are accepted and ignored. Redelivered events report "duplicate": true.
Status | Cause |
|---|---|
| A Recurly or BigCommerce connection has no API credentials yet, so the event can't be read. The provider retries it. |
| Signature (or Basic auth, or BigCommerce's secret header) did not verify. Check that |
| Unknown connection id, or the connection is not active. |
GET /v1/billing/events?customerRef=… shows what was received for a customer. An event with no customer id at all (one Referalli can't attribute) is acknowledged with 200 and skipped, so the provider doesn't retry it.
Manage a connection
Call | Purpose |
|---|---|
| Your connections: |
| One connection. |
| Pause ( |
| For connections where Referalli issued the secret: a new |
| For providers that issue the secret themselves (Stripe, Paddle, Polar, Shopify): roll it there, then set it here. The old one also keeps verifying for 24 hours. |
| Delete for good: the webhook URL stops answering and the secrets and API credentials are wiped. Payments and commissions it recorded stay. |
All of these need owner or admin and are audited. The same actions are on Settings → Billing providers.