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:

  1. Sign in to AI Content Drop with your account.
  2. Open Settings → Integrations.
  3. 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"

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.