FrawlFrawl Handbook

Merchant integration

Install tracking, bind a customer, and verify a commission safely.

Merchant integration

Use a test program first. The setup screen shows program, integration, click and attributed-sale checks from persisted records. A completed form alone does not mark the integration verified.

Browser and server boundary

Install /sdk/v1.js from your tracking domain asynchronously; the exact attributes and consent API are documented in packages/tracker/README.md and apps/tracking/README.md. Use only program-registered destination origins. The SDK receives a signed reference containing no PII. Never put a secret API key in a browser. When consent is denied, do not create durable visitor identity.

Before checkout, send the reference from your backend to POST /api/v1/referrals/claim:

{
	"programId": "your-program-id",
	"customerId": "stable-customer-id",
	"reference": "signed-referral-reference",
	"destinationOrigin": "https://your-store.example"
}

Authenticate with a test/live API key scoped to referrals:write. Use the same stable customer ID in payment metadata or custom events. Cookie availability is browser-dependent; server claims survive later cookie deletion. Cross-domain handoff requires an explicitly allowed destination.

Provider connections

Each connection has an independent webhook URL and encrypted credentials. Configure the provider to send events to POST /api/v1/webhooks/{provider}/{connectionId}. Supported IDs are stripe, paddle, lemonsqueezy, moyasar, tap, paytabs, and custom.

The SDK has no authority to declare revenue or a commission. Provider native capabilities are returned by /api/v1/capabilities; the UI shows those capabilities. See packages/affiliate/README.md for signature algorithms, canonical financial keys and unsupported reconciliation cases.

ProviderConfirmed sale sourceNotes
StripePaid invoice or independent successful payment intentInvoice-backed payment intents are not double-counted
PaddleCompleted transactionRefund and chargeback adjustments
Lemon SqueezySubscription invoice or one-time orderInitial-payment aliases prevent duplicate credit
MoyasarTrusted API payment with paid/captured statusJSON secret_token plus retrieval; custom lifecycle supplements
TapTrusted CAPTURED chargehashstring plus retrieval of unsigned fields
PayTabsSuccessful Sale/CaptureRaw-body signature; refund links to original transaction
CustomAuthenticated canonical eventStable customer/payment/adjustment identities required

Custom events

POST /api/v1/events requires a scoped events:write API key and Idempotency-Key header. The full contract is served at /api/v1/openapi.json. Example sale:

{
	"id": "evt_sale_001",
	"connectionId": "your-custom-connection",
	"type": "payment.succeeded",
	"occurredAt": "2026-09-22T12:00:00Z",
	"customerId": "stable-customer-id",
	"paymentId": "stable-payment-id",
	"currency": "USD",
	"amountMinor": "4900",
	"taxMinor": "0",
	"eligibleMinor": "4900"
}

All amounts are decimal integer strings in minor units. Do not submit a commission amount. For refunds include a stable adjustmentId and explicit refundMode (incremental or cumulative). For recurring commission duration and MRR include subscription identity, paid period and cadence. Unknown tax/attribution data leaves the sale pending; it must not silently produce an inaccurate commission.

Replaying the same event/key with a different payload is a conflict. Retry network failures with the same stable key. A 202 response means durable reception, not necessarily a completed commission.

Verify the result

  1. Open a real affiliate link in the test program and grant tracking consent when appropriate.
  2. Bind the reference on the merchant server before checkout.
  3. Complete a provider sandbox payment or send a signed custom test event.
  4. Verify the conversion, recorded attribution evidence, rule version, fraud decision and ledger.
  5. Repeat the event; totals must stay unchanged. Send a partial refund and verify the reversal.
  6. Prepare a payout with one account, approve it with another authorized account, export it and record an external confirmation. Exporting alone never marks money paid.

First/last touch uses server-recorded touch order. Renewal attribution is pinned to the original eligible subscription association. MRR is unavailable without valid paid subscription data; CTR is unavailable without impressions; ROI requires program cost records. Currencies remain separate.

On this page