> ## 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.

# Events API

> Server-to-server endpoint for sending events to Thrad.

Send events to Thrad directly from your backend — useful when the action happens server-side (subscription renewal, fulfillment, async lead qualification) or when you want delivery that survives ad-blockers and ITP.

The payload shape mirrors the [Tag's event call](/advertisers/attribution/tag/events) — same event names, same free-form `params` bag — but you authenticate with a [bearer API key](/advertisers/attribution/server-api/authentication) and the server stamps `channel = "server"` on every row.

## Endpoint

```
POST https://events.thrad.ai/api/collect
Authorization: Bearer <YOUR_API_KEY>
Content-Type: application/json
```

## Request

```bash theme={null}
curl -X POST https://events.thrad.ai/api/collect \
  -H "Authorization: Bearer $THRAD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "tag_id":     "<YOUR_TAG_ID>",
    "event_name": "items_added",
    "event_id":   "evt_42",
    "timestamp":  1748275200,
    "click_id":   "clk_xyz",
    "session_id": "sess_abc",
    "params": {
      "content_id": "sku_123",
      "quantity": 2,
      "value": 58.00,
      "currency": "USD"
    }
  }'
```

## Body

Only `event_name` is required. Everything else is optional — pass what you have.

| Field                                 | Type   | Notes                                                                                                   |
| ------------------------------------- | ------ | ------------------------------------------------------------------------------------------------------- |
| `event_name`                          | string | **Required.** Standard ([see taxonomy](/advertisers/attribution/tag/events#standard-events)) or custom. |
| `tag_id`                              | string | Your tag ID. If omitted, the server derives one from `page_url` host.                                   |
| `event_id`                            | string | For deduplication / idempotency.                                                                        |
| `timestamp`                           | number | Unix seconds. Defaults to server receive time.                                                          |
| `page_url`, `referrer`, `user_agent`  | string | Browser context, when known.                                                                            |
| `session_id`, `client_id`             | string | Your stable user identifiers.                                                                           |
| `click_id`, `impression_id`, `bid_id` | string | Attribution IDs captured from the original ad click.                                                    |
| `attribution_type`                    | string | `click` / `view` / `organic`.                                                                           |
| `consent`                             | object | GDPR/CCPA consent flags.                                                                                |
| `params`                              | object | Free-form properties. Stored as JSON; queryable in reporting.                                           |

## Response

```
HTTP/1.1 204 No Content
```

Fire-and-forget. A `204` means the event was accepted for storage. There's no per-event validation feedback beyond the basic shape check.

## What the server adds

The server enriches every row before insert:

* `ip_address` — from the request
* `geo_country`, `geo_region`, `geo_city`, `geo_lat`, `geo_lon` — from IP lookup
* `ua_browser`, `ua_os`, `ua_device`, … — parsed from your `user_agent`
* `channel = "server"` — overrides whatever you passed

## Idempotency

Pass a stable `event_id` to dedupe retries — used as the dedup key in reporting joins.
