SplitChamp

The API

Four endpoints run the whole program: claim links, record clicks, record sales. Your site keeps its checkout and its policies; SplitChamp keeps the attribution, the commission math, the partner dashboards, and the emails.

Base URL & auth

https://api.splitchamp.com/v1 Authorization: Bearer sc_live_…

Every request carries your account's API key as a Bearer token. Find it — and roll it — in your admin dashboard. Keys are stored hashed and shown once at mint time. Errors come back as { "error": "<code>" } with a meaningful HTTP status; missing or wrong keys get 401.

How attribution works

Attribution travels as an opaque sealed token. When you record a click, SplitChamp returns one; you store it in a first-party cookie on your domain and hand it back on later clicks and at sale time. You never parse it — inside are the partner, a stable visitor identity, and the click, HMAC-signed and expiry-checked server-side. Tokens live 30 days; each new click re-seals with the newest link, so attribution is last-click.

POST/links

Claims a vanity link, creating the partner behind it. Whether someone is allowed to claim (invitations, approvals) is your policy, enforced before you call.

{ "slug": "miarivers", "displayName": "Mia Rivers", "email": "mia@example.com", "externalId": "invite-abc123" // optional } // 201 { "slug": "miarivers", "commissionRate": 0.5, "dashboardUrl": "https://splitchamp.com/dash/miarivers" }

email is where sale notifications go and doubles as the partner's passwordless login. Pass an externalId (an invitation id, a user id — any stable string) to enforce one link per person: repeat claims with the same id return the existing link with 200 and "alreadyClaimed": true instead of erroring. Slugs are 3–30 chars of a-z 0-9 -, minus a reserved list. Errors: 409 slug_taken, 422 slug_invalid | slug_reserved | email_invalid | missing_fields.

GET/links/{slug}

Availability check for claim forms. 200 returns the link (slug, displayName, createdAt); 404 means the slug is free.

POST/clicks

Call from your redirect route (e.g. your /i/{slug} handler), set the returned token as a cookie, and redirect. Where the visitor lands is yours to decide — the recommended pattern is to let the partner say it in the URL itself: /i/{slug} goes to your default page, and /i/{slug}/{path} (e.g. /i/miarivers/deep4) goes to that page. Nothing to configure, and one partner can promote as many products as they like.

{ "slug": "miarivers", "ip": "203.0.113.7", "userAgent": "Mozilla/5.0 …", "referer": "https://youtube.com/watch?v=…", "attribution": "<visitor's existing cookie value, if any>" } // 200 { "attribution": "<sealed token>", "ttlDays": 30 } Set-Cookie: sc_attr=<token>; Max-Age=2592000; Path=/; HttpOnly; SameSite=Lax; Secure; Domain=<your registrable domain>

Passing the visitor's prior token keeps their identity stable across visits, so unique-visitor counts stay honest. Set the cookie's Domain to your bare domain so it works on www. and the apex alike. Preview bots and crawlers are recorded but filtered out of partner-facing stats automatically. Errors: 404 unknown_link, 422 missing_fields.

POST/sales

Call from your payment webhook when the buyer carried an sc_attr cookie. No cookie → no call.

{ "attribution": "<cookie value>", "product": "DEEP/4", "amountCents": 10000, "processorFeeCents": 548, // optional "currency": "usd", "provider": "paypal", "paymentRef": "5AB29344TN081234X", "buyerName": "Jordan Lee", // optional "buyerEmail": "jordan@example.com", // optional "occurredAt": "2026-07-23T12:22:33Z" // optional, defaults to now } // 201 (or 200 on replay of the same paymentRef) { "commissionCents": 5000, "feeShareCents": 274, "netCents": 4726, "partner": "miarivers" }

Idempotent on paymentRef — retry your webhook freely; replays return the original result. The money model: commission = floor(amount × rate); the partner's share of the processor fee scales with their rate (fee × commission ÷ amount); net = commission − fee share. SplitChamp emails the partner their cut the moment the sale lands, with the account owner BCC'd. Omit the fee if you don't have it — fee share is 0 until known. Errors: 422 attribution_invalid | amount_invalid | fee_invalid | occurred_at_invalid | missing_fields.

POST/views

Optional but recommended: report page views by visitors carrying the sc_attr cookie, and partners see which pages their traffic actually looks at ("Where your visitors go" on their dashboard). Fire and forget — call it from middleware or an edge hook for requests that have the cookie; don't block the page on it.

{ "attribution": "<cookie value>", "path": "/deep4", "userAgent": "Mozilla/5.0 …" // optional, used for bot filtering } // 204 No Content

Query strings are stripped server-side; bot traffic is filtered from the stats. Errors: 422 attribution_invalid | missing_fields.

A complete integration

Three thin touch points in your codebase:

1. Redirect route → POST /clicks, set sc_attr cookie, redirect 2. Claim form → GET /links/{slug} to check, POST /links to claim 3. Payment webhook → POST /sales with the sc_attr cookie value 4. (optional) middleware → POST /views for cookie-carrying page views

That's the whole surface. Partners sign in at splitchamp.com with the email you passed at claim time — magic link, no passwords — and see their clicks, visitors, sales, and earnings.

Not in v1

Refund reversal, payout marking via API, read/reporting endpoints, and multiple links per partner are planned. The API is additive: v1 request and response shapes won't change out from under you.