Developer docs

Conversion pixel and server API

Conversion tracking attributes browser or server events to Linkube redirects. A conversion-enabled redirect appends lkid only after its PostgreSQL touch is durable.

Browser pixel

Create a publishable installation token under Workspace → Setup & Attribution, then copy the one-time token/snippet before closing it. The token is high-entropy, workspace-bound, revocable, and grants ingestion only; it cannot access the panel or management APIs. The SDK reads ?lkid=, stores it as lk_click_id in localStorage and a first-party cookie, then posts to /api/v1/conversions/events.

htmlInstall
<script
  src="https://linkube.io/api/v1/pixel.js"
  data-installation-token="lkpub_example_publishable_installation_token"
  async
></script>
javascriptTrack after checkout/signup
const conversionEvent = ["purchase", {
  event_id: order.id, // stable across retries of this order
  value: 49.99,
  currency: "USD",
  custom_data: { plan: "pro" }
}];

if (typeof window.linkube?.track === "function") {
  window.linkube.track(...conversionEvent);
} else {
  window.linkube = window.linkube || { q: [] };
  window.linkube.q = window.linkube.q || [];
  window.linkube.q.push(conversionEvent);
}

Allowed browser hostnames

Allowed domains are an origin risk control, not authentication: non-browser clients can forge or omit Origin. Entries are exact, lowercase hostnames without schemes, ports, paths, or wildcards. An empty list allows all origins. When the list is nonempty, a missing origin or a hostname not in the list returns 403. The installation token remains the workspace identity.

Server conversions

For confirmed purchases or account events, POST the V2 contract to /api/v1/conversions/server with an active workspace API key. The workspace and source are derived from the key and endpoint, so callers cannot spoof another workspace.

bashcURL
curl -X POST https://linkube.io/api/v1/conversions/server \
  -H "Authorization: Bearer lk_live_example_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "action_key": "purchase",
    "lkid": "19b54b0b-7708-4b86-9b7e-ac1cbb24dd66",
    "event_id": "order_12345",
    "occurred_at": "2026-09-30T12:00:00Z",
    "value": 49.99,
    "currency": "USD",
    "metadata": { "plan": "pro" },
    "test_mode": false
  }'
javascriptNode.js
await fetch("https://linkube.io/api/v1/conversions/server", {
  method: "POST",
  headers: {
    Authorization: "Bearer lk_live_example_api_key",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    action_key: "purchase",
    lkid: checkoutUrl.searchParams.get("lkid"),
    event_id: order.id,
    occurred_at: new Date().toISOString(),
    value: order.total,
    currency: "USD",
    metadata: { plan: order.plan },
    test_mode: false,
  }),
});

Edge cases

  • Missing lkid: send null or omit it. The event remains durable but is unattributed.
  • Canonical V2 browser and server events require a caller-stable event_id; use an order or transaction identity and reuse it for every retry of that business event. Two invocations with different IDs are two events. The browser SDK makes one transport attempt and does not provide delivery acknowledgement or automatic retry, so the calling application owns retry policy. The legacy server adapter can generate an ID when omitted, but that cannot deduplicate caller retries.
  • Idempotency identity is workspace + action_key + event_id. A new event returns 202 with receipt_id, event_id, status, and duplicate: false. An identical retry returns 200 with the same receipt and duplicate: true; a different canonical payload returns 409.
  • occurred_at is the timezone-aware business-event time. received_at is assigned on durable PostgreSQL acceptance and projected_at records analytical projection. Attribution requires clicked_at <= occurred_at <= expires_at; Wave 0 uses a fixed 30-day touch expiry and does not expose a configurable attribution window.
  • value is an optional decimal with at most six fractional digits. When value is present, a three-letter currency is required and normalized to uppercase.
  • Missing/invalid installation or API credentials return 401; installation workspace/origin mismatch returns 403; validation returns 422.
  • Rate limits return 429 with Retry-After. A canonical event that receives a durable rate-limited decision keeps that decision on identical retries; Retry-After applies to new traffic or a genuinely new business event, not reevaluation under a new ID. Installation-token database lookup failure returns 503 CONVERSION_IDENTITY_UNAVAILABLE; API-key database lookup failure returns 503 API_KEY_IDENTITY_UNAVAILABLE. Invalid credentials remain 401. Durable acceptance and limiter failures use their own stable 503 codes.
  • If durable touch persistence fails or times out, the Short Link still redirects but omits lkid; that navigation cannot later be attributed through the failed touch.
  • The older event_name/click_id/custom_data server shape remains accepted for compatibility, but new integrations should use the V2 fields shown above.