> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.ada.cx/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.ada.cx/_mcp/server.

# End Users API

For [Messaging identity tokens](/messaging/identity/getting-started), your backend creates an end user or looks one up by `external_id`. Pass the resulting identity token to the SDK; the conversation creation flow below remains specific to custom channels.

The End Users API allows you to create, update, and manage your end users' data in real time. It also comes with webhook events you can subscribe to so you can keep track of changes to user profiles in Ada.

Download full OpenAPI spec

This API allows integrators to:

* **Create end users with context before a conversation starts.** Use `POST /v2/end-users/` to set language, metadata, and sensitive metadata before calling `POST /v2/conversations/`. The AI Agent has full user context from the first turn.
* **Identify end users with a stable external ID.** Use the optional `external_id` field on `POST /v2/end-users/`, `PATCH /v2/end-users/{end_user_id}`, and `GET /v2/end-users/?external_id=<value>` to reference end users by your own identifier (for example a CRM contact ID or a phone number) across conversations.
* Programmatically sync user details from external systems with Ada using webhooks so that Action and Knowledge rules apply to those users.
* Get notified at your [webhook endpoint](#webhook-support) when Ada users are created or updated through the API.
* Update metavariables using request blocks or Actions.
  * The `end_user_id` is a variable that will fill in this part of the URL programmatically for requests or actions (so you don't have to consume webhooks unless needed).
* **Pass sensitive metadata securely.** Use the `sensitive_metadata` field to provide auth tokens, session IDs, or personally identifiable information through an encrypted, write-only pathway.

## Channel eligibility

| Feature                                                                  | Available channels                                               |
| ------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| `external_id` field on `POST`, `PATCH`, and `GET /v2/end-users/`         | Custom channels and backend lookup for Messaging identity tokens |
| Pre-greeting context (`POST /v2/end-users/` → `POST /v2/conversations/`) | Custom channels (Conversations API) only                         |
| Sensitive metadata on `POST /v2/end-users/`                              | Backend end-user creation                                        |
| Sensitive metadata on `PATCH /v2/end-users/:id`                          | All channels (endpoint is channel-agnostic)                      |

For legacy Chat, the Chat SDK provides [`setMetaFields()`](/chat/web/sdk-api-reference#setmetafields) and [`setSensitiveMetaFields()`](/chat/web/sdk-api-reference#setsensitivemetafields) as the primary path. For social and email channels, `PATCH /v2/end-users/:id` with `sensitive_metadata` is the only API pathway for passing sensitive values.

> **Warning**
>
> End users created through `POST /v2/end-users/` that are not associated with a conversation within 24 hours of creation are automatically deleted. To prevent deletion, start a conversation for the end user via `POST /v2/conversations/` before the 24-hour window elapses.

For end-to-end integration patterns, see the [developer guide](/reference/end-users/developer-guide).

## User profile structure

The End User Profile entity is represented as a JSON object composed of `key,value` pairs. Each key in the End User object represents a metavariable you can use throughout Ada. [Learn more about metavariables](/docs/optimization/personalization/personalization-data).

You can use the `profile.metadata` object to create a custom mapping of key, value pairs to reflect your company's
data schema. All values must be strings, integers, or booleans.

The `system_properties` object includes select keys automatically created by Ada, and is read-only. Note that depending on your Ada configuration, not all keys defined in the End Users API specification may be present or may have values.

> **Warning**
>
> The end user profile is composed of metavariables, which may be set through Ada's embed SDK as well as through the End Users API. Use caution when storing user information in metavariables - they are not intended to replace an authentication flow to verify a user's identity and information.

## Sensitive metadata

The `sensitive_metadata` field is available on both `POST /v2/end-users/` and `PATCH /v2/end-users/:id`. It provides a secure pathway for passing values that should not be stored in standard metadata.

Sensitive metadata values are:

* **Encrypted at rest** in Ada's storage layer
* **Redacted from the dashboard** and not visible to operators
* **Excluded from LLM context** and never sent to the AI model
* **TTL-bound** and automatically deleted after 24 hours
* **Write-only** and never returned in API responses (GET or PATCH)

This matches the security contract of the Chat SDK's [`setSensitiveMetaFields()`](/chat/web/sdk-api-reference#setsensitivemetafields).

Use `sensitive_metadata` for auth tokens, session IDs, and personally identifiable information. Use standard `metadata` for non-sensitive context like region and plan type.

Additional constraints:

* Maximum **20 key-value pairs** per request.
* On `PATCH`, keys must match the pattern `[A-Za-z0-9_-]+`.
* On `POST`, sensitive metadata keys must not overlap with keys in the sibling `metadata` field.

> **Warning**
>
> Sensitive metadata is stored at the end-user level, not the conversation level. If an end user has multiple active conversations, a value set in one conversation is accessible in all of them. For the most common integration pattern (one end user per conversation), this is not observable.

The `sensitive_metadata` field is nested inside `profile` and contains a `fields` object. To remove a sensitive metavariable, set the key to `null`:

```json
{
  "profile": {
    "sensitive_metadata": {
      "fields": {
        "auth_token": null
      }
    }
  }
}
```

## External ID

The `external_id` field is an optional, caller-supplied identifier on the end user object. It lets custom-channel integrations reference end users by a stable identifier from another system (for example a CRM contact ID or a phone number) instead of Ada's `end_user_id`.

* **Top-level field.** `external_id` sits alongside `end_user_id` on the end user object, not inside `profile`.
* **Unique per AI Agent.** One `external_id` maps to exactly one end user within an AI Agent.
* **Case-insensitive.** `ABC-123` and `abc-123` are treated as the same value.
* **Length and characters.** Maximum 36 characters. The `<` and `>` characters are not allowed.
* **Set on create or update.** Pass `external_id` in `POST /v2/end-users/` or `PATCH /v2/end-users/{end_user_id}`.
* **Idempotent create.** If `POST /v2/end-users/` is called with an `external_id` that is already mapped, the existing end user is returned with HTTP `200` instead of creating a duplicate. A new end user returns HTTP `201`.
* **Clear on PATCH.** Setting `external_id` to `null` in a `PATCH` request removes the mapping and frees the value to be assigned to a new end user.
* **Lookup.** `GET /v2/end-users/?external_id=<value>` returns the matching end user or `404`.

Custom channels use `external_id` for end-user lookup. Messaging backends can use the same lookup before minting an identity token. For end users created through non-custom channels, `external_id` is `null` on the end user object and in webhook payloads.

For an end-to-end example, see [Identify end users with a stable external ID](/reference/end-users/developer-guide#identify-end-users-with-a-stable-external-id).

## Webhook support

Ada uses webhook events to keep your systems in sync. These events allow your systems to track and react to key moments related to specific user actions and updates. The following events are supported:

* [`v1.end_user.created`](/reference/end-users/end-user-created-webhook): Triggered when a new user is created through any of Ada's supported channels, including explicit creation via `POST /v2/end-users/`. The AI Agent's customer persistence setting influences the rate of these events.
* [`v1.end_user.updated`](/reference/end-users/end-user-updated-webhook): Triggered when a value on the end user's profile changes. Updates may occur via:
  * API calls (e.g., PATCH requests to the End Users API).
  * Updates through Ada-supported channels (e.g., `setMetafields` on embeds).
  * Profile field mappings from Sunshine Conversations.

For implementation details, see the [webhook documentation](/reference/webhooks/overview).

> **Info**
>
> **If you use IP allowlisting:** Ada delivers webhooks through Svix. If your firewall only accepts traffic from approved source IPs, review [this section](/reference/webhooks/overview#ip-allowlist) for full details.

### Changes that do not trigger events

Certain updates do not generate `end_user.updated` events:

* Changes to system.properties.
* Modifications to metavariables like:
  * ip\_address
  * user\_agent
  * browser
  * device
  * last\_answer\_id
  * channel\_status
* Changes to `sensitive_metadata` (write-only values do not trigger update events).

For more details on how to implement and use webhooks, refer to the [webhook documentation](/reference/introduction/webhooks).

## Rate limits

`/v2/end-users/` and `/v2/end-users/<end_user_id>` adhere to these rate limits:

* No daily limit
* Requests per minute: 300
* Requests per second: 30

All other End Users API endpoints, including bulk deletion, adhere to our
[global rate limits](/reference/introduction/limits).