Authentication
One header, two kinds of token. Which one you want depends on whose account the work belongs to.
Every request carries Authorization: Bearer <token>. There is no query-parameter form and no cookie form: the API is called from your server, and a token in a URL ends up in access logs. A missing, unknown, revoked or expired token gets 401 unauthorized with a WWW-Authenticate: Bearer realm="vidmoat" header.
| Use | Token | Whose account |
|---|---|---|
| API key, server to server | vmk_live_… or vmk_test_… | Yours. Everything it generates bills you. |
| OAuth access token, acting for a user | 64 hex characters | The user who granted consent. Always live. |
API keys#
Mint one in Apps. The plaintext is shown once and never again: only a SHA-256 hash is stored, so a leaked key is fixed by revoking it and minting another, not by looking it up.
Test and live#
- Test keys are free on every plan. They never spend credits and never queue a real render, but projects and edits they make are real. See test and live keys.
- Live keys need three things: the developer agreement accepted, the app approved in review, and a plan with live API access (Studio, Team or Enterprise). A live key can spend real credits.
Sign in with Vidmoat (OAuth 2.0)#
When your product edits your user's videos rather than your own, you want an access token for them, not your key. Vidmoat speaks OAuth 2.0 authorization code with PKCE, plus RFC 7591 dynamic client registration. Discovery metadata is where you expect it:
| Step | Endpoint |
|---|---|
| Authorize (the user consents here) | https://www.vidmoat.com/oauth/authorize |
| Exchange the code, refresh a token | POST https://api.vidmoat.com/api/oauth/token |
| Register a client dynamically | POST https://api.vidmoat.com/api/oauth/register (10 an hour per IP) |
- Grants:
authorization_codeandrefresh_token. Client authentication:client_secret_postorclient_secret_basic. - Use PKCE with
S256. (plainis accepted for older MCP clients; do not choose it.) - Redirect URIs are allowlisted per client and support an
https://prefix*form, because some connector platforms mint a fresh callback per install. - The consent screen lists the scopes you ask for, with the ones that can spend credits flagged, using the same descriptions as the scope reference.
- For a client that belongs to a developer app, access tokens last 1 hour and refresh tokens 90 days, rotating on every use. Store the newest refresh token each time.
- Users can see and revoke every app they connected at
https://www.vidmoat.com/oauth/connected. A revoked grant fails with401on the next call. - OAuth tokens are clamped to the scopes the user consented to and to your app's scope ceiling.
What the credential does not change#
A token identifies a real Vidmoat user, always. There are no anonymous sub-identities, and that is deliberate: every generated frame is attributable to an account with a monitored contact address, which is what makes moderation and takedown possible. Plan limits, credit balance, export allowance and content moderation apply to the token's owner exactly as they do in the editor.
So a scope is necessary but never sufficient. A key carrying ai.video on a plan without video generation still returns 402 plan_required. Read scopes next.
When a request is refused#
| Status | Code | Meaning |
|---|---|---|
| 401 | unauthorized | No token, or one that is unknown, revoked or expired. |
| 403 | insufficient_scope | The token lacks a scope. The error names it (scope) and lists what you have (granted). |
| 403 | access_suspended | The owning account is restricted. restriction says what, until when and how to appeal. |
| 403 | app_suspended | The app's kill switch is on, independent of the account. |