# TubeExtract auth.md: agent registration

You are an agent. TubeExtract is an API that turns YouTube videos into typed JSON rows. It supports **agentic registration**: you ask for access on behalf of a person, the person confirms with a six-digit code, and you collect a workspace API key. Follow the steps in order.

If the person already gave you a TubeExtract API key, skip all of this and go to [Step 5](#step-5--use-the-key).

## What this is, and is not

- **Agent audience:** agents and applications calling `https://api.tubeextract.dev/v1` for a person: submitting video URLs with a schema and collecting the extracted rows.
- **Method offered:** verified email (`service_auth`). The person must have a TubeExtract account, or create one when they open the link (sign up at https://tubeextract.dev/signup, 3,000 free credits, no card).
- **Not offered:** anonymous registration, ID-JAG identity assertions, or creating an account for a person. You cannot get a key without the person confirming.
- **Credential:** a workspace API key (`tbx_live_...`) as the `access_token`. It does not expire. The person can revoke it any time in the dashboard, and you can revoke it at `/oauth2/revoke`.

## Step 1 — Discover

An unauthenticated call to the API returns `401` with the metadata location:

```http
WWW-Authenticate: Bearer resource_metadata="https://api.tubeextract.dev/.well-known/oauth-protected-resource"
```

- Protected Resource Metadata, from the API itself: https://api.tubeextract.dev/.well-known/oauth-protected-resource (the same facts are also at https://tubeextract.dev/.well-known/oauth-protected-resource)
- Authorization Server metadata, with the `agent_auth` block: https://tubeextract.dev/.well-known/oauth-authorization-server

`agent_auth.register_uri` is where you register, `agent_auth.claim_endpoint` is where you ask for a fresh code, and `token_endpoint` is where you collect the key.

## Step 2 — Register

Before sending this, tell the person you are about to ask TubeExtract for an API key in their name, for their workspace, to submit jobs and spend its credits, and get their agreement. You need their email address.

```http
POST https://api.tubeextract.dev/agent/identity
Content-Type: application/json

{ "type": "service_auth", "login_hint": "person@example.com", "agent_name": "Your agent's name" }
```

Response (200):

```json
{
  "registration_id": "reg_...",
  "registration_type": "service_auth",
  "claim_url": "https://api.tubeextract.dev/agent/identity/claim",
  "claim_token": "clm_...",
  "claim_token_expires": "2026-10-05T12:00:00.000Z",
  "post_claim_scopes": ["api"],
  "claim": {
    "user_code": "123456",
    "expires_in": 600,
    "verification_uri": "https://tubeextract.dev/claim?claim_attempt_token=cla_...",
    "interval": 5
  }
}
```

Hold `claim_token` in memory. It is returned once and is how you collect the key. `agent_name` is shown to the person on the confirmation page.

## Step 3 — Hand off to the person

Give them the `verification_uri` and the `user_code` in one message:

> Open this link, sign in as person@example.com, and type this six-digit code on the page: **123456**
> https://tubeextract.dev/claim?claim_attempt_token=...

The code goes into the page, not back to you. Only the account for the email you named can confirm, so a stranger who sees the link cannot claim it. The code is good for 10 minutes and allows 5 wrong tries.

## Step 4 — Poll for the key

```http
POST https://api.tubeextract.dev/oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=clm_...
```

Poll every `interval` seconds (5). Answers:

| Response | What it means | What to do |
| --- | --- | --- |
| `400 authorization_pending` | The person has not confirmed yet | Keep polling |
| `400 slow_down` | You polled too fast | Wait longer between polls |
| `400 expired_token` | The code timed out; the registration is still open | `POST /agent/identity/claim` with `{"claim_token": "...", "email": "person@example.com"}` for a new code, show it, resume polling |
| `400 access_denied` | The person cannot create keys here, or the workspace's plan has no key slots left | Tell the person; they can revoke a key in the dashboard, then you poll again |
| `400 invalid_grant` | The registration expired (24 hours), or the key was already collected | Start again at Step 2 |
| `200` | Confirmed | Take `access_token` |

Success:

```json
{ "access_token": "tbx_live_...", "token_type": "Bearer", "scope": "api" }
```

The key is returned exactly once. Store it where you keep secrets.

## Step 5 — Use the key

```
curl https://api.tubeextract.dev/v1 \
  -H "X-API-Key: tbx_live_..." \
  -H "Content-Type: application/json" \
  -d '{"videos": ["https://www.youtube.com/watch?v=..."], "multiple": true, "schema": [{"name": "topic", "type": "string"}]}'
```

`Authorization: Bearer tbx_live_...` works too. A missing or invalid key returns `401`. The same key works for the MCP server at `https://api.tubeextract.dev/mcp`.

## Step 6 — Revoke

```http
POST https://api.tubeextract.dev/oauth2/revoke
Content-Type: application/x-www-form-urlencoded

token=tbx_live_...
```

Always answers `200`. Use it when the task is done or the key may have leaked.

## More

- Authentication reference: https://tubeextract.dev/docs/authentication
- Quickstart: https://tubeextract.dev/docs/quickstart
- OpenAPI description: https://tubeextract.dev/openapi.json
