> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thrads.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversion API

> Server-to-server endpoint for reporting conversions to Thrad.

Send conversions to Thrad directly from your backend — the most reliable path, since it bypasses the browser entirely.

Unlike the [Tag's conversion call](/advertisers/attribution/tag/conversions), the server endpoint trusts you via your [API key](/advertisers/attribution/server-api/authentication) instead of a signed click — so you don't need to pass `sig` / `exp`. You do need to pass the `click_id` your site captured on landing (we use it to join the conversion back to the original ad).

## Endpoint

```
POST https://events.thrad.ai/api/conversion
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json
Idempotency-Key: order_123          ← optional but recommended
```

## Request

```bash theme={null}
curl -X POST https://events.thrad.ai/api/conversion \
  -H "Authorization: Bearer $THRAD_API_KEY" \
  -H "Idempotency-Key: order_123" \
  -H "Content-Type: application/json" \
  -d '{
    "click_id":         "clk_xyz",
    "conversion_time":  "2026-05-26T12:34:56Z",
    "conversion_value": 99.99,
    "currency":         "USD",
    "order_id":         "order_123",
    "event_type":       "purchase_completed"
  }'
```

## Body

| Field                                | Type              | Required    | Notes                                                                                                                                          |
| ------------------------------------ | ----------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `click_id`                           | string            | yes         | The click ID captured by the Tag on the original landing URL.                                                                                  |
| `conversion_time`                    | ISO-8601 datetime | yes         | When the conversion happened.                                                                                                                  |
| `conversion_value`                   | number            | yes         | Monetary value of the conversion.                                                                                                              |
| `currency`                           | string (3)        | yes         | 3-letter ISO (`USD`, `EUR`, …).                                                                                                                |
| `event_type`                         | string            | no          | Defaults to `"purchase_completed"`. Use other names for non-purchase conversions (`subscription_created`, `trial_started`, `lead_created`, …). |
| `order_id`                           | string            | recommended | Used for deduplication when no `Idempotency-Key` is sent.                                                                                      |
| `event_id`                           | string            | no          | Explicit dedup key. The `Idempotency-Key` header takes precedence if both are sent.                                                            |
| `tag_id`                             | string            | no          | Override if you operate multiple tags under one partner key.                                                                                   |
| `page_url`, `referrer`, `user_agent` | string            | no          | Browser context, when known.                                                                                                                   |
| `session_id`, `client_id`            | string            | no          | Your stable user identifiers.                                                                                                                  |

Any additional keys are accepted and stored under `params.extra`.

## Response

```json theme={null}
{ "status": "ok" }
```

Or, when a duplicate is detected:

```json theme={null}
{ "status": "duplicate" }
```

## Deduplication

Two layers, in priority order:

1. **`Idempotency-Key` header** — strongest. The same key + `click_id` + `event_type` within the dedup window returns `duplicate` and writes nothing.
2. **`order_id`** — used as a fallback dedup key when no idempotency header is sent. This makes retries of a payment-webhook handler safe.

Always send one of the two. Without either, a retried HTTP request will create a second conversion row.

## Errors

| Status | Body                                       | Cause                                                                           |
| ------ | ------------------------------------------ | ------------------------------------------------------------------------------- |
| `401`  | `Missing bearer token` / `Invalid API key` | Auth. See [Authentication](/advertisers/attribution/server-api/authentication). |
| `404`  | `Click not found`                          | The `click_id` you sent doesn't exist in our click store.                       |
| `400`  | `Click missing bid id`                     | The click record exists but can't be attributed to a bid.                       |
| `422`  | Pydantic validation error                  | Required field missing or wrong type.                                           |
