# Exchange application credentials for a short-lived widget JWT

> Exchange application credentials for a short-lived widget JWT: CustomDomain™ API reference in the tokens group. Covers parameters, request body and responses.

Source: https://docs.customdomain.ai/docs/api-reference/tokens/createWidgetToken

## `POST https://api.customdomain.ai/v1/tokens`

Server-side only. Trade an application's `client_secret` for a short-lived widget JWT the browser can use on the Connect endpoints. Never ship the `client_secret` or an API key to the browser.

### Authentication

None.

### Request body (JSON)

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `application_id` | string | yes |  |
| `client_secret` | string | yes |  |
| `domain` | string | no | Optional. Binds the token to a single hostname. |
| `domains` | array of string | no | Optional. A list of hostnames the token may act on, so a multi-domain flow needs one token instead of one per domain. Each entry is normalized and duplicates and blanks are dropped. Additive to `domain`; omit both for a token that is not bound to a hostname. |
| `end_user_ref` | string | no | Optional. Binds the token to one end user: your own id for them. A connection created with the token is stamped with it (a different `end_user_ref` in the create body is refused), and an end user's token removes a domain, or reads its monitoring, services and timeline, only when it is bound to the domain and minted with the connection's own `end_user_ref`. |
| `end_user_email` | string | no | Optional. The email address of the end user this token is for. It is never put in the token: it is kept on our side and a connection created with this token takes it, so that after a Move the person gets the new DNS records by email on your behalf. An `end_user_email` on the connection create wins over it. |
| `scope` | `connect`, `app` | no | `connect` (the default) is an END USER's token for the widget: it runs the connect flow for a domain (check, create, read its own connection, verify, one-click and OAuth starts, sharing, telemetry, diagnose) and nothing else, because it lives in that end user's browser. `app` lets your server act as the whole application (list every connection, manage webhooks, configure SSL and Power, bulk create, purchases). Never hand an `app` token to a browser. |

### Responses

| Status | Description |
| --- | --- |
| `201` | Token issued |
| `400` | Error envelope: {code, title, details}. |
| `401` | Error envelope: {code, title, details}. |
| `429` | `rate_limited`: too many token requests from this address, or too many failed ones (unknown application or wrong secret) for this `application_id`. A request with the right secret is limited only by its address. Retry shortly. |

### `201` response body

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `token` | string | yes | the widget JWT (Bearer) |
| `token_type` | string | yes |  |
| `expires_in` | integer | yes | lifetime in seconds (default 900) |
| `scope` | `connect`, `app` | no | the scope the token was minted with |

The full specification is served at `GET https://api.customdomain.ai/v1/openapi.json`.
