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 the Authorization header. 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 TypeNotes
click_idrequiredstring ≤200The tabs_cid value from the cookie or URL parameter.
conversion_typerequiredstring ≤80What happened: "signup", "purchase", "trial", any label you segment by.
conversion_valueoptionalnumber ≥ 0Monetary value. Feeds the deal's return and the spend-to-return multiple.
currencyoptionalstring (3 letters)Uppercased automatically. Defaults to "USD".
customer_emailoptionalstring ≤255Lowercased and validated. Makes this a named customer on the deal.
customer_nameoptionalstring ≤255Display name for the customer record.
customer_idoptionalstring ≤255Your internal id, for joining back to your systems.
metadataoptionalobjectFree-form JSON stored with the conversion (plan, source, anything).
public_keyoptionalstringPixel 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 that click_id. Also returned when the click belongs to another workspace, so the response never reveals what exists.
  • 429: rate limited. Honor the Retry-After header (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_cid cookie 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_type values; both attribute to the deal.

Questions or a missing capability? The Developers panel has a live cURL builder wired to your real keys.