Skip to content
OpenTrain AIOpenTrain AIOpenTrain AIDocs

Ask OpenTrain

Answers from the documentation, with sources.

What would you like to do with OpenTrain?

AI answers can be mistaken. Check the linked sources. Don’t include private account information.

Open app

DEVELOPER DOCUMENTATION

Create Token

Mint a new personal API token. New tokens can never exceed the caller's scopes — the secret is shown once.

POST/api/public/v1/tokens

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.

This endpoint always mints fixed fine-grained scopes — the explicit list you request, or a clone of the caller’s current scopes. Full-access keys, which automatically expand to current and future self-serve scopes, can only be created in Developer Settings in the web app; the API cannot mint one.

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.

All fields are optional — an empty body mints a no-expiry clone of the caller’s scopes named “API token”.

namestringbody

Label for the token (max 120 chars). Defaults to API token.

scopesstring[]body

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

expiresAtstringbody

ISO 8601 timestamp in the future after which the token stops working. Defaults to no expiry.

Returns 201.

tokenstring

The plaintext ot_pat_… secret. Shown once — store it now.

tokenTypestring

bearer.

metadataobject

The token record: {id, name, preview, scopes, status: "active", organizationId, createdAt, lastUsedAt, expiresAt, revokedAt} — same shape as the entries in GET /tokens.

StatuscodeMeaning
400BAD_REQUESTBody 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
401UNAUTHORIZEDMissing or invalid token
403FORBIDDENRequested scopes exceed the caller’s (details.requestedScopes, details.grantedScopes, details.escalatedScopes)
409CONFLICTActive token limit reached (25) — revoke unused tokens first