Tokens
Create Token
Mint a new personal API token. New tokens can never exceed the caller’s scopes — the secret is shown once.
POST
Mints a new
ot_pat_ personal API token on the account. This is how you hand a narrowly-scoped token to a sub-agent or integration, set an expiry on automation credentials, and rotate a token (create the replacement, switch over, then revoke the old one).
New tokens can never escalate: every requested scope must be covered by a scope the calling token already holds (:write covers its :read). Accounts hold at most 25 active tokens.
The plaintext token is returned only in this response — store it immediately. Afterwards only the masked preview is visible via GET /tokens.
Requirements: any valid token — token management needs no specific scope or feature flag, and works pre-claim.
This endpoint is HTTP-only: no CLI command or MCP tool wraps it. Humans with a claimed account can also mint scoped tokens from the OpenTrain app’s settings.
Request
All fields are optional — an empty body mints a no-expiry clone of the caller’s scopes named “API token”.Label for the token (max 120 chars). Defaults to
API token.Scopes for the new token, from the scope catalog. Defaults to the calling token’s scopes. Every entry must be covered by the caller’s scopes (
403 otherwise).ISO 8601 timestamp in the future after which the token stops working. Defaults to no expiry.
Response
Returns201.
The plaintext
ot_pat_… secret. Shown once — store it now.bearer.The token record:
{id, name, preview, scopes, status: "active", organizationId, createdAt, lastUsedAt, expiresAt, revokedAt} — same shape as the entries in GET /tokens.Errors
| Status | code | Meaning |
|---|---|---|
400 | BAD_REQUEST | Body not valid JSON; name empty or over 120 chars; scopes not a string array or contains unknown scopes (details.unknownScopes, details.supportedScopes); expiresAt not a valid ISO timestamp or not in the future |
401 | UNAUTHORIZED | Missing or invalid token |
403 | FORBIDDEN | Requested scopes exceed the caller’s (details.requestedScopes, details.grantedScopes, details.escalatedScopes) |
409 | CONFLICT | Active token limit reached (25) — revoke unused tokens first |