AI Content Drop API Authentication
The short version
Send Authorization: Bearer acd_live_… on any request that touches an account or spends credits. Everything else — the model catalogue, cost quotes, articles, the GraphQL schema, the MCP read tools — works with no credential at all.
If the human has no account yet
An agent cannot finish a signup — it has no mailbox and cannot accept terms on someone's behalf — but it can start one and hand the person a single clear step.
POST https://aicontentdrop.com/v1/auth/register
Content-Type: application/json
{ "email": "[email protected]" }
Returns 202 with status: "human_action_required" and a message_for_human line written to be repeated verbatim. The person receives a sign-in link; opening it creates the account, confirms the address, and releases the free credits.
There is no password parameter, and that is deliberate. An agent holding a user's password is a credential-custody problem that no rate limit fixes, so the flow is magic-link only.
Credits are released on confirmation, not on signup. An account created this way holds 0 credits until the human clicks the link, at which point the 10 free credits appear. That is what stops programmatic signup from being a free-credit faucet — an IP limit alone would not, because IPs rotate.
An address that already has an account gets exactly the same response, so this endpoint cannot be used to test who is registered here.
Limited to 5 registrations per hour per IP; a 429 carries Retry-After.
While you wait
Do not block on the human. These need no account at all:
| Want | Call |
|---|---|
| The model catalogue | GET https://aicontentdrop.com/v1/models |
| What a generation costs | GET https://aicontentdrop.com/v1/models/{id}/cost |
| The generation contract, without spending | POST https://aicontentdrop.com/v1/generate/video with X-Sandbox: true |
| An answer in prose | GET https://aicontentdrop.com/ask?q=... |
| A read-scope token | POST https://aicontentdrop.com/agent/auth/register |
Getting a key
A key belongs to a person, not to an agent, and only a signed-in human can mint one:
- Sign in to AI Content Drop with your account.
- Open Settings → Integrations.
- Create a key. It is shown once. Store it; we keep only a hash.
Keys are prefixed acd_live_. A key carries the plan, credit balance, and rate ceiling of the account that owns it. Revoking a key is immediate.
Discovering all of this from one request
An agent that hits a protected endpoint without a credential gets a 401 that says where to look:
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="AI Content Drop",
resource_metadata="https://aicontentdrop.com/.well-known/oauth-protected-resource"
/.well-known/oauth-protected-resource— RFC 9728 protected-resource metadata/.well-known/oauth-protected-resource/mcp: the same document at the RFC 9728 path-suffixed location, and the pointer the MCP endpoint's own 401 carries/.well-known/oauth-authorization-server— RFC 8414 authorization-server metadata/auth.md— the same thing as prose, in the seven sections agents expect: discover, pick a method, register, claim, use, errors, revoke
Protected-resource metadata
The resource in that document is the exact MCP URL, https://aicontentdrop.com/mcp, not the site origin. A host that follows the MCP authorization spec compares this value with the URL it connected to and binds its token to it; both discovery locations above return identical JSON so the comparison holds whichever one the host tried first. scopes_supported lists only what the issuer actually mints: openid, email, profile, and offline_access (the one that lets a host keep a refresh token instead of asking the person to sign in again every hour). The issuer supports authorization code with PKCE (S256), public clients, and dynamic client registration (RFC 7591): its registration_endpoint is in the metadata, so a host that registers itself needs nothing from us beforehand.
A valid token that lacks the scope a tool needs gets a 403 whose WWW-Authenticate carries error="insufficient_scope" and names the missing scope, so a client can re-authorize for exactly that.
Agent self-registration
An agent with no human behind it can register for a read-scoped token:
curl -sX POST https://aicontentdrop.com/agent/auth/register \
-H "Content-Type: application/json" \
-d '{"client_name":"my-agent"}'
That token raises read rate limits. It cannot generate — generation spends money, and money needs an account a person owns. The endpoints are POST /agent/auth/register, /agent/auth/claim, and /agent/auth/revoke; only anonymous identity is supported, which the metadata says explicitly rather than implying more.
Verifying us
Requests our own crawlers make to other sites are signed with Ed25519 (RFC 9421 HTTP Message Signatures, Web Bot Auth). The public key is at /.well-known/http-message-signatures-directory, and the same key backs the did:web:aicontentdrop.com identity in /.well-known/did.json that our ARD catalogue entries are signed against.
What a key can reach
| Surface | Anonymous | With a key |
|---|---|---|
GET /v1, /v1/models, cost quotes |
yes | yes |
| GraphQL public fields, SDL, introspection | yes | yes |
| MCP read tools (catalogue, articles) | yes | yes |
| MCP generation tools | listed, not callable | callable |
/v1/me, generation, history |
no | yes |
Where an OAuth token works
A token obtained through the OAuth sign-in (the one a host such as Claude, ChatGPT, Kimi Code or Perplexity holds for you) reaches the MCP server at /mcp — every tool, including the account and generation tools — and the generation endpoints under /v1 (POST /v1/generate/video, POST /v1/generate/image). The rest of the REST API (/v1/me, /v1/videos) takes an API key; an OAuth host reads its account and its jobs through the MCP tools instead. A generation started with an OAuth token or an API key never takes the zero-credit unlimited lane a paid plan has in the web app: the decision is read from the credential itself, not from a header the caller chooses to send.
An OAuth token is not a website session. The website's own /api/* routes — settings, API-key creation, checkout, profile sync, logout — refuse it with 403, a body carrying code: "oauth_client_token_not_accepted", and WWW-Authenticate: Bearer error="insufficient_scope", whichever client it was issued to. The refusal is decided from the token's client_id claim, which the issuer sets and a client cannot remove without breaking the signature.