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

# SDK Event Submission

> Capture logins, gameplay and session activity from the device with a scoped credential - subject binding and network context enforced server-side.

Most [events](/transaction-monitoring/events) that matter for fraud happen on the device: the login, the session, the gameplay round, the timing telemetry that separates a person from a script. The device lane sends them without putting an API key in a browser.

Your backend mints a short-lived credential scoped to one user; the app posts events with it.

## Flow

<Steps>
  <Step title="Mint a monitoring credential">
    Your backend calls `POST /v3/events/sdk-token/` with your API key and the user's `vendor_data`.
  </Step>

  <Step title="Submit from the device">
    The app posts to `POST /v1/events/` (or `POST /v1/events/batch/`) with the `X-Monitoring-Token` header.
  </Step>

  <Step title="Rules run as usual">
    The event is enriched, rolled up and evaluated by exactly the same [rules](/transaction-monitoring/event-rules) as a server-submitted one.
  </Step>
</Steps>

## Minting a credential

```bash theme={null}
curl -X POST https://verification.didit.me/v3/events/sdk-token/ \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "vendor_data": "user_391",
    "allowed_event_categories": ["auth", "session", "gameplay"],
    "ttl_seconds": 900,
    "max_uses": 1000,
    "bind_to_origin": "https://operator.example"
  }'
```

```json theme={null}
{
  "monitoring_token": "…",
  "expires_at": "2026-08-31T21:00:00Z",
  "allowed_event_categories": ["auth", "session", "gameplay"],
  "max_uses": 1000,
  "bind_to_origin": "https://operator.example"
}
```

| Field                      | Default      | Notes                                                              |
| -------------------------- | ------------ | ------------------------------------------------------------------ |
| `vendor_data`              | required     | The subject every event submitted with this credential belongs to. |
| `entity_type`              | `individual` | `individual` or `company`.                                         |
| `allowed_event_categories` | all          | Narrow what a leaked credential could write.                       |
| `ttl_seconds`              | 900          | 60 - 86400.                                                        |
| `max_uses`                 | 1000         | One use per **event**, not per request.                            |
| `bind_to_origin`           | none         | When set, the browser `Origin` must match exactly.                 |

## Submitting

```bash theme={null}
curl -X POST https://verification.didit.me/v1/events/ \
  -H "X-Monitoring-Token: THE_MINTED_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event_id": "session-abc-login-1",
    "event_category": "auth",
    "action_type": "login",
    "occurred_at": "2026-08-31T20:40:31.123Z",
    "session": { "session_id": "web-session-abc", "sequence": 1 },
    "device_context": { "fingerprint": "didit-fp-v2:a8c1" },
    "payload": { "method": "password" }
  }'
```

Note what the payload does **not** carry: no API key, and no subject. Both are enforced server-side.

## What the server enforces

* **Subject binding.** The credential is scoped to one `vendor_data` at mint time. A `subject` block in the request body is overwritten, so a tampered client cannot write to another user's timeline.
* **Network context.** The IP address, user agent, accept-language and origin are derived from the request, and those server-derived values win over any client hint for rule evaluation. Rule evidence records the difference as a [field source](/transaction-monitoring/event-rules#evidence).
* **Category scope.** A credential scoped to `session` cannot submit a `payment` event; it is rejected with `400`.
* **Use budget.** A batch spends one use per event, so a 500-event batch cannot slip past a 10-use credential as a single use.
* **Origin binding.** When `bind_to_origin` is set, a request whose `Origin` does not match is refused - including one with no `Origin` at all.

## Batching

```bash theme={null}
curl -X POST https://verification.didit.me/v1/events/batch/ \
  -H "X-Monitoring-Token: THE_MINTED_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "events": [ { "…": "…" }, { "…": "…" } ] }'
```

Up to 500 events per flush, with the same per-item outcomes as the [server batch endpoint](/transaction-monitoring/events#batches). A good default flush is 25 events, 5 seconds, or page/app backgrounding.

### What to drop under backpressure

If you have to shed events, shed the cheap ones. These are safe to drop:

`session.page_view` · `session.sdk_heartbeat` · `session.sdk_loaded` · `session.device_seen` · `session.bot_signal_observed` · `bonus.promotion_viewed` · `affiliate.referral_clicked`

These are not - flush them first:

every `security`, `payment`, `dispute` and `responsible_gambling` event, plus `gameplay.bet_placed`, `gameplay.bet_settled` and `gameplay.p2p_settlement`.

The list endpoints return the same classification per event as `is_droppable`, so a client can be driven by it rather than by a hardcoded copy.

## Header compatibility

The canonical header is `X-Monitoring-Token`. `X-Transaction-Token` is accepted as a temporary alias so an app that already holds a transaction credential path can migrate incrementally.

<Warning>
  The alias is transitional and will be removed before the events API reaches general availability. Send `X-Monitoring-Token` in new code.
</Warning>

## Choosing a lane

|          | Device lane                           | Server lane                                          |
| -------- | ------------------------------------- | ---------------------------------------------------- |
| Endpoint | `POST /v1/events/`                    | `POST /v3/events/`                                   |
| Auth     | `X-Monitoring-Token`                  | `x-api-key`                                          |
| Subject  | Bound to the credential               | In the payload                                       |
| Best for | Logins, sessions, gameplay, telemetry | Payments, disputes, ledger-derived events, backfills |

Both produce identical event records and run identical rules. Use the server lane whenever no end user is present.

## Next

<CardGroup cols={2}>
  <Card title="Event ingestion" icon="bolt" href="/transaction-monitoring/events">
    The envelope, categories, retention and idempotency.
  </Card>

  <Card title="Rules on events" icon="filter" href="/transaction-monitoring/event-rules">
    Velocity, ratio, sequence and correlation rules.
  </Card>
</CardGroup>
