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

# Mint Monitoring SDK Token

> Mint a short-lived device credential bound to one subject so your app can submit monitoring events without exposing your API key.



Mint Monitoring SDK Token API Prompt
        Copy prompt to clipboard



      
      

\<pre>

\`Mint a short-lived device credential so my web or mobile app can send monitoring events for one user straight to Didit.

Endpoint:
POST https://verification.didit.me/v3/events/sdk-token/

Authentication:
Use the x-api-key header with my Didit API key. This call runs on MY BACKEND only - the API key must never ship in an app. Only the returned monitoring_token travels to the device. A scoped key needs transactions: write.

Goal:
\- Get a monitoring_token for the signed-in user. The app sends it in the X-Monitoring-Token header to the device lane (POST /v1/events/ and POST /v1/events/batch/).

Request body (application/json):
\{
"vendor_data": "user-42",                                  // required - the subject every event belongs to
"entity_type": "individual",                               // optional - company binds a company; any other value an individual (default)
"allowed_event_categories": ["auth", "session", "gameplay"], // optional - omit or [] for every category
"ttl_seconds": 900,                                        // optional - 60 to 86400, default 900
"max_uses": 1000,                                          // optional - events it may submit, default 1000, null for no cap
"bind_to_origin": "https://app.example.com"                // optional - browser Origin must match exactly
}
camelCase aliases (vendorData, entityType, allowedEventCategories, ttlSeconds, maxUses, bindToOrigin) are also accepted.

Behavior:
\- The subject is bound server-side: whatever subject the app sends is overwritten with vendor_data.
\- One use per submitted event, also inside a batch: a 500-event flush spends 500 uses, and events the device lane rejects spend uses too.
\- An event outside allowed_event_categories is rejected by the device lane with 400.
\- With bind_to_origin set, a device request with a different Origin, or none, is refused.
\- Minting does not create a user.
\- Event ingestion must be switched on for the application, otherwise this call returns 403 with code event_monitoring_disabled.

Example call:
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-42","allowed_event_categories":["auth","session","gameplay"],"ttl_seconds":900,"max_uses":1000}'

What to read from the response:
\- monitoring_token - hand it to the app; treat it as a secret for its lifetime.
\- expires_at - mint a fresh credential per user session before it expires.
\- allowed_event_categories ([] means every category), max_uses (null means no cap), bind_to_origin.

Failure modes:
\- 400 - missing vendor_data, ttl_seconds outside 60-86400, max_uses below 1, or an unknown category.
\- 401 - the API key has expired.
\- 403 - missing or invalid API key, a scoped key without transactions: write, or code event_monitoring_disabled.

Side effects: creates one credential. Nothing else changes.

For the full client-side submission guide, see /transaction-monitoring/sdk-event-submission.`

\</pre>



      
      

Paste into

The credential is consumed by the device lane, described in [SDK event submission](/transaction-monitoring/sdk-event-submission.md), which also lists what the server enforces on every device request and which events are safe to drop under backpressure.


## OpenAPI

````yaml POST /v3/events/sdk-token/
openapi: 3.0.0
info:
  version: 3.0.0
  title: Didit Verification API
  description: Identity verification API. Authenticate with x-api-key header.
servers:
  - url: https://verification.didit.me
security: []
tags: []
paths:
  /v3/events/sdk-token/:
    post:
      tags:
        - Monitoring Events
      summary: Mint monitoring SDK token
      description: >-
        Mint a short-lived device credential bound to one subject, so your web
        or mobile app can send that user's events straight to Didit without an
        API key. The app sends the returned `monitoring_token` in the
        `X-Monitoring-Token` header to the device lane (`POST /v1/events/` and
        `POST /v1/events/batch/`), where the subject is always overwritten with
        this `vendor_data`, events outside `allowed_event_categories` are
        rejected, each submitted event spends one use, and a request whose
        `Origin` does not equal `bind_to_origin` is refused. Call it from your
        backend only; minting creates the credential and nothing else (no user
        is created). Event ingestion must be switched on for the application,
        otherwise this endpoint returns `403` with `code:
        event_monitoring_disabled` instead of minting a credential that could
        never write. A scoped API key needs `transactions: write`. See [SDK
        event
        submission](https://docs.didit.me/transaction-monitoring/sdk-event-submission).
      operationId: create_monitoring_event_sdk_token
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: >-
                camelCase aliases are accepted: `vendorData`, `entityType`,
                `allowedEventCategories`, `ttlSeconds`, `maxUses`,
                `bindToOrigin`.
              required:
                - vendor_data
              properties:
                vendor_data:
                  type: string
                  minLength: 1
                  maxLength: 255
                  description: >-
                    Your id for the subject every event submitted with this
                    credential belongs to.
                entity_type:
                  type: string
                  maxLength: 32
                  default: individual
                  description: >-
                    `company` binds a company subject; any other value (default
                    `individual`) binds an individual.
                allowed_event_categories:
                  type: array
                  items:
                    type: string
                    enum:
                      - auth
                      - session
                      - gameplay
                      - bonus
                      - affiliate
                      - payment
                      - dispute
                      - security
                      - responsible_gambling
                      - custom
                  description: >-
                    Categories the credential may submit. Omit it or send `[]`
                    to allow every category.
                ttl_seconds:
                  type: integer
                  minimum: 60
                  maximum: 86400
                  default: 900
                  description: Lifetime of the credential in seconds.
                max_uses:
                  type: integer
                  minimum: 1
                  nullable: true
                  default: 1000
                  description: >-
                    Number of events the credential may submit (a batch spends
                    one use per event). Send `null` for no cap within the
                    lifetime.
                bind_to_origin:
                  type: string
                  maxLength: 255
                  nullable: true
                  description: >-
                    When set, the browser `Origin` header of every device
                    request must equal this value exactly; a request without
                    `Origin` is refused.
            example:
              vendor_data: user-42
              allowed_event_categories:
                - auth
                - session
                - gameplay
              ttl_seconds: 900
              max_uses: 1000
              bind_to_origin: https://app.example.com
      responses:
        '201':
          description: >-
            The credential was minted. Hand `monitoring_token` to the app and
            treat it as a secret until `expires_at`.
          content:
            application/json:
              schema:
                type: object
                required:
                  - monitoring_token
                  - expires_at
                  - allowed_event_categories
                  - max_uses
                  - bind_to_origin
                properties:
                  monitoring_token:
                    type: string
                    description: >-
                      The device credential (a 43-character URL-safe token).
                      Send it in the `X-Monitoring-Token` header.
                  expires_at:
                    type: string
                    format: date-time
                    description: When the credential stops being accepted.
                  allowed_event_categories:
                    type: array
                    items:
                      type: string
                      enum:
                        - auth
                        - session
                        - gameplay
                        - bonus
                        - affiliate
                        - payment
                        - dispute
                        - security
                        - responsible_gambling
                        - custom
                    description: >-
                      Categories the credential may submit; `[]` means every
                      category.
                  max_uses:
                    type: integer
                    nullable: true
                    description: Event budget of the credential; null means no cap.
                  bind_to_origin:
                    type: string
                    nullable: true
                    description: Origin the credential is bound to, or null.
              example:
                monitoring_token: q7ZtR2xKp9VbN4mWc8LdH1sYfJ3gT6uEaQ0oPiXzBkC
                expires_at: '2026-10-17T09:30:02.481000Z'
                allowed_event_categories:
                  - auth
                  - session
                  - gameplay
                max_uses: 1000
                bind_to_origin: https://app.example.com
        '400':
          description: >-
            Validation failed: missing `vendor_data`, `ttl_seconds` outside 60
            to 86400, `max_uses` below 1, or an unknown category (keyed by its
            position in the array).
          content:
            application/json:
              examples:
                Missing vendor_data:
                  value:
                    vendor_data:
                      - This field is required.
                ttl_seconds too short:
                  value:
                    ttl_seconds:
                      - Ensure this value is greater than or equal to 60.
                Unknown category:
                  value:
                    allowed_event_categories:
                      '1':
                        - '"login" is not a valid choice.'
        '401':
          description: >-
            The scoped API key has expired. Only an expired key gets `401`; a
            missing or invalid key gets `403`.
          content:
            application/json:
              examples:
                Expired key:
                  value:
                    detail: This API key has expired.
        '403':
          description: >-
            Missing or invalid `x-api-key` (this endpoint answers `403`, never
            `401`, for a missing or invalid key), a scoped key without
            `transactions: write`, a key limited to some workflows or to
            approved sessions (such a key never reaches transaction monitoring
            data), or a request from outside the key's IP allowlist. Also
            returned with `code: event_monitoring_disabled` while event
            ingestion is switched off for the application; nothing is stored in
            that case, and the check runs before the body is validated.
          content:
            application/json:
              examples:
                Event monitoring disabled:
                  value:
                    detail: >-
                      Event monitoring is not enabled for this application. Turn
                      on event ingestion in the transaction monitoring settings
                      before submitting events.
                    code: event_monitoring_disabled
                Missing or invalid API key:
                  value:
                    detail: You do not have permission to perform this action.
                Scoped key without access:
                  value:
                    detail: This API key has no write access to transactions.
                Key limited to workflows or approved sessions:
                  value:
                    detail: >-
                      This API key only reaches sessions inside its workflow or
                      status limits, so it can't use this endpoint.
                IP not allowed:
                  value:
                    detail: This API key can't be used from this IP address.
        '429':
          description: >-
            Rate limit exceeded: write requests (`POST`, `PATCH`, `DELETE`)
            share a budget of 300 requests per minute per API key. Wait
            `Retry-After` seconds, then retry.
          headers:
            Retry-After:
              description: Seconds to wait before retrying.
              schema:
                type: integer
                minimum: 1
                example: 30
          content:
            application/json:
              examples:
                Throttled:
                  value:
                    detail: >-
                      Write request rate limit exceeded. You can make up to 300
                      requests per minute.
      security:
        - ApiKeyAuth: []
      x-codeSamples:
        - lang: curl
          label: curl
          source: |-
            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-42",
                "allowed_event_categories": ["auth", "session", "gameplay"],
                "ttl_seconds": 900,
                "max_uses": 1000,
                "bind_to_origin": "https://app.example.com"
              }'
        - lang: python
          label: Python
          source: |-
            import os

            import requests

            resp = requests.post(
                'https://verification.didit.me/v3/events/sdk-token/',
                headers={'x-api-key': os.environ['DIDIT_API_KEY']},
                json={
                    'vendor_data': 'user-42',
                    'allowed_event_categories': ['auth', 'session', 'gameplay'],
                    'ttl_seconds': 900,
                    'max_uses': 1000,
                    'bind_to_origin': 'https://app.example.com',
                },
                timeout=10,
            )
            resp.raise_for_status()
            credential = resp.json()
            # Hand only monitoring_token to the app, never the API key.
            print(credential['monitoring_token'], credential['expires_at'])
        - lang: javascript
          label: JavaScript
          source: >-
            const resp = await
            fetch('https://verification.didit.me/v3/events/sdk-token/', {
              method: 'POST',
              headers: {
                'x-api-key': process.env.DIDIT_API_KEY,
                'Content-Type': 'application/json',
              },
              body: JSON.stringify({
                vendor_data: 'user-42',
                allowed_event_categories: ['auth', 'session', 'gameplay'],
                ttl_seconds: 900,
                max_uses: 1000,
                bind_to_origin: 'https://app.example.com',
              }),
            });

            if (!resp.ok) throw new Error(await resp.text());

            const { monitoring_token, expires_at } = await resp.json();

            // Hand only monitoring_token to the app, never the API key.

            console.log(monitoring_token, expires_at);
components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        Your application's API key, from Developers -> API keys in the Business
        Console. The primary key has full access. A named key can be scoped:
        none, read or write per resource, limited to some workflows or to
        approved sessions, to a list of IP addresses, and to an expiry date. 401
        means the key is missing, wrong, revoked or expired; 403 means the key
        has no access to this resource or action, or the request came from an
        address outside its IP list; 404 on a session route means the session is
        outside the key's workflows or statuses. A key without media access
        receives image, video and PDF URLs as null, and a key without sessions
        write receives session links and tokens as null. See
        https://docs.didit.me/console/api-keys.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.