Campaign SDK

Send trusted outcomes from your backend

Use the conversions endpoint for completed business outcomes that should become server-verified campaign evidence. Every request needs the signed assignment and the confidential installation key.

Carry the assignment to your backend

A decision assignment includes an origin-bound, signed token. Send that token to your own backend alongside the action that may later convert. Keep your customer record and PII in your system. tday needs the attribution token, not the person's identity.

Browser to your application
const decision = await campaign.ready;
const assignmentToken = decision?.assignments[0]?.token;

await fetch("/api/checkout", {
  method: "POST",
  headers: { "content-type": "application/json" },
  body: JSON.stringify({
    productId: "team-plan",
    assignmentToken
  })
});

Post the completed conversion

When the outcome is durable, send one event to POST https://tday.com/api/sdk/v1/conversions. Use an ID derived from the durable operation so a worker retry sends the same ID again.

Server-side TypeScript
const conversion = {
  id: `order_${order.publicId}`, // stable across retries
  name: "purchase_completed",             // exact campaign primary event
  assignmentToken: order.assignmentToken,
  occurredAt: order.completedAt.toISOString(),
  valueMinor: order.totalMinor,
  currency: "USD",
  properties: {
    plan: order.planKey,
    billingCycle: order.billingCycle
  }
};

const response = await fetch(
  "https://tday.com/api/sdk/v1/conversions",
  {
    method: "POST",
    headers: {
      authorization: `Bearer ${process.env.TDAY_CAMPAIGN_SECRET}`,
      "content-type": "application/json"
    },
    body: JSON.stringify(conversion)
  }
);

if (!response.ok) {
  throw new Error(`Campaign conversion failed: ${response.status}`);
}

const result = await response.json();
// { ok: true, accepted: 1, duplicates: 0 }
cURL
curl https://tday.com/api/sdk/v1/conversions \
  -H "Authorization: Bearer $TDAY_CAMPAIGN_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
    "id": "order_01J8M6Y7QK",
    "name": "purchase_completed",
    "assignmentToken": "td_at_signed_assignment_token",
    "occurredAt": "2026-08-26T18:30:00.000Z",
    "valueMinor": 12900,
    "currency": "USD",
    "properties": { "plan": "team" }
  }'

Make the event count

Match the primary event exactly

The event name must exactly equal the campaign's configured lowercase primary event to enter event-based optimizer evidence. Valid custom names are stored, but they do not count as the primary conversion.

Stay inside the attribution window

A primary conversion must follow the signed assignment and occur within the campaign attribution window. The timestamp cannot be over five minutes in the future or more than 90 days old.

Use the campaign currency

If valueMinor is present, include a three-letter currency code. It must match the campaign currency. The value is a non-negative integer in minor units.

Reuse the event ID on retry

IDs allow 1 to 128 safe letters, numbers, periods, underscores, tildes, or hyphens. Reusing one within the installation returns it as a duplicate instead of adding another conversion.

Send a batch

Batch one to 50 events with the conversions wrapper. The endpoint also accepts one event directly, a conversionwrapper, or an events array.

JSON
{
  "conversions": [
    {
      "id": "order_01J8M6Y7QK",
      "name": "purchase_completed",
      "assignmentToken": "td_at_signed_assignment_token",
      "occurredAt": "2026-08-26T18:30:00.000Z",
      "valueMinor": 12900,
      "currency": "USD"
    }
  ]
}

Trust and provider evidence

Accepted endpoint events are stored with server-verified trust. tday also reconciles aggregate conversions reported by connected paid providers as provider-verified evidence. Provider aggregates do not need a browser event-name match, and overlapping sources are combined conservatively rather than blindly added together.

Continue reading