API reference
Conversion API
Last updated · July 19, 2026
Report signups and purchases against your tracked links so every deal shows real ROI. Two ways in: a server-to-server webhook (recommended) and a browser pixel for sites without a backend hook.
How attribution works
Every tracked link redirects through sponsr.dev/r/<slug>. The redirect does three things: appends your UTM parameters, sets a first-party tabs_cid cookie (a random click id, 30-day window), and appends ?tabs_cid=…to your landing URL so the id survives even when cookies don't. When that visitor later signs up or buys, you send the click_id back with the conversion. sponsr matches it to the click, the link, and the deal.
No click id, no attribution: a conversion for an unknown click_id returns 404 and records nothing.
API keys
Keys live in Settings → Developers. There are two kinds, and they are not interchangeable:
- Secret key (
tabs_pk_…): server-only. Authenticates the webhook via theAuthorizationheader. Never ship it to a browser. - Public key (
tabs_pub_…): safe in HTML. It can do exactly one thing (create conversions through the pixel), so exposing it costs you nothing.
Quick start
Fastest path: the script tag. Add this to your thank-you or post-signup page. It reads tabs_cid from the cookie or the URL and reports the conversion; if there is no click id it does nothing.
<script
src="https://sponsr.dev/track.js"
data-key="tabs_pub_your_key"
data-conversion="signup"
data-value="99.00"
data-currency="USD"
data-customer-email="customer@example.com"
></script>Server-side: the webhook. Store the visitor's tabs_cid at signup, then post the conversion when it happens (at signup, at purchase, or both with different types):
curl -X POST https://sponsr.dev/api/v1/conversion \
-H "Authorization: Bearer tabs_pk_your_key" \
-H "Content-Type: application/json" \
-d '{
"click_id": "the tabs_cid value",
"conversion_type": "purchase",
"conversion_value": 290.00,
"currency": "USD",
"customer_email": "k.tanaka@example.com",
"metadata": { "plan": "team" }
}'POST /api/v1/conversion
Server-to-server. Authenticate with your secret key: Authorization: Bearer tabs_pk_…. Body is JSON (the fields below, without public_key).
// 201 Created
{ "id": "9f3c…", "status": "recorded" }POST /api/v1/conversion/pixel
The browser endpoint /track.js calls for you; call it directly only if you need custom behavior. Same fields as the webhook plus public_key in the body; no Authorization header. CORS is open (Access-Control-Allow-Origin: *) with an OPTIONS preflight, because it runs on your domain.
Fields
| Field | Type | Notes | |
|---|---|---|---|
| click_id | required | string ≤200 | The tabs_cid value from the cookie or URL parameter. |
| conversion_type | required | string ≤80 | What happened: "signup", "purchase", "trial", any label you segment by. |
| conversion_value | optional | number ≥ 0 | Monetary value. Feeds the deal's return and the spend-to-return multiple. |
| currency | optional | string (3 letters) | Uppercased automatically. Defaults to "USD". |
| customer_email | optional | string ≤255 | Lowercased and validated. Makes this a named customer on the deal. |
| customer_name | optional | string ≤255 | Display name for the customer record. |
| customer_id | optional | string ≤255 | Your internal id, for joining back to your systems. |
| metadata | optional | object | Free-form JSON stored with the conversion (plan, source, anything). |
| public_key | optional | string | Pixel endpoint only: the tabs_pub_… key. The webhook uses the Authorization header instead. |
Blank strings in optional fields are treated as absent, so empty pixel data-attributes are safe.
Responses & errors
201: recorded. Returns{ "id": "…", "status": "recorded" }.400: invalid JSON or a field failed validation. The body names the first failing field.401: missing or invalid key (or the wrong kind of key for the endpoint).404: no matching click for thatclick_id. Also returned when the click belongs to another workspace, so the response never reveals what exists.429: rate limited. Honor theRetry-Afterheader (seconds).500: the conversion could not be stored. Safe to retry.
Rate limits & windows
- 100 requests per minute per key, on both endpoints.
- 30-day attribution window: the
tabs_cidcookie lives 30 days from the click. The URL parameter has no expiry of its own; capture it server-side at signup if your funnel outlives the cookie. - Conversions are stored as they arrive. If you send both a signup and a later purchase for the same click, use two
conversion_typevalues; both attribute to the deal.
Questions or a missing capability? The Developers panel has a live cURL builder wired to your real keys.