# Registering for an API key

The free tier needs no key. A key raises the rate limit, raises the scan cap and lets scans be attributed to an account. Registration is one POST with one field.

## Request

```bash
curl -s -X POST https://www.agentpass.page/api/keys \
  -H "content-type: application/json" \
  -d '{"email":"agent@example.com","plan":"pro"}'
```

## Response — 201 Created

```json
{
  "key": "ap_live_9f2c41c7b8e04d3a",
  "prefix": "ap_live_9f2c",
  "plan": "pro",
  "scopes": ["scan:read", "scan:write"],
  "rateLimit": { "limit": 60, "window": "1m" },
  "createdAt": "2026-11-09T18:20:00.000Z"
}
```

The key is shown once. Store it as `AGENTPASS_API_KEY`; never put it in a URL.

## Using the key

```bash
curl -s "https://www.agentpass.page/api/scan?url=https://example.com" \
  -H "Authorization: Bearer $AGENTPASS_API_KEY"
```

## Scopes

| Scope | Allows |
|---|---|
| `scan:read` | read cached reports, badges, /last |
| `scan:write` | start a new scan, including paid scans |

Scopes are advertised in `https://www.agentpass.page/.well-known/oauth-authorization-server` under `scopes_supported`, and the protected resource metadata lives at `https://www.agentpass.page/.well-known/oauth-protected-resource`.

## Errors

| Status | Body | Meaning |
|---|---|---|
| 400 | `{"title":"Invalid email"}` | the email field failed validation |
| 409 | `{"title":"Account exists"}` | that email already has a key; rotate instead |
| 429 | `{"title":"Too many registrations"}` | 5 per hour per IP |

Rotation: `POST /api/keys/rotate` with the current key in the Authorization header returns a new key and invalidates the old one after a five-minute grace period.
