# auth.md — QuanticData

> How an AI agent, or the developer running one, obtains and uses credentials for QuanticData: the Data API at `https://api.quanticdata.io/v1`, the proxy networks, and the hosted MCP server at `https://api.quanticdata.io/mcp`. One file, read top to bottom. Machine-readable companions: [protected resource metadata](https://api.quanticdata.io/.well-known/oauth-protected-resource/mcp) (RFC 9728), [authorization server metadata](https://app.quanticdata.io/.well-known/oauth-authorization-server) (RFC 8414), [API catalog](https://quanticdata.io/.well-known/api-catalog) (RFC 9727), [OpenAPI](https://quanticdata.io/docs/openapi.json), [docs](https://quanticdata.io/docs/), [llms.txt](https://quanticdata.io/llms.txt).

## 1. Who this is for, and which credential you need

| You want to call | Credential | How it is issued |
| --- | --- | --- |
| Data API — `https://api.quanticdata.io/v1/*` (scrape, search, crawl, map, batch, SEO audit, collectors, proxy generation, account) | API key `qd_live_…` | Created by a person in the dashboard, or by an agent via verified-email registration (section 2) |
| MCP server — `https://api.quanticdata.io/mcp` (Streamable HTTP) | OAuth 2.1 access token **or** the same API key | OAuth: your MCP client signs the user in; API key: as above |
| Proxy networks (residential, mobile, datacenter, IPv6, ISP) | Proxy username/password per plan | Issued in the dashboard after a plan is active, or listed through the Data API with your key (`GET /v1/public/proxies`, `POST /v1/public/proxies/generate`) |

There is one account for everything: API usage and proxy plans draw on the same balance, and an API key belongs to that account.

## 2. Registration: by a human, or by an AI agent with a verified email

Two ways to get an account and an API key `qd_live_…`:

- **A person**: register at `https://app.quanticdata.io/register`, open `https://app.quanticdata.io/api-keys`, create a key (shown once), hand it to the agent.
- **An agent, by itself** (Auth.md, method `verified_email`): the agent sends the email address of the person it works for; QuanticData emails that person a 6-digit code; the person gives the code to the agent; the agent exchanges it for an API key. No password, no browser, no captcha. The machine-readable block is `agent_auth` in the [authorization server metadata](https://app.quanticdata.io/.well-known/oauth-authorization-server). Anonymous registration and ID-JAG assertions are not offered.

What each account can use for free, the request limits per tier and the price of every call are published and kept current at `https://quanticdata.io/docs/` (section "Rate limits and tiers") and in the OpenAPI document. This file does not repeat numbers.

### 2a. Agent registration (verified email) — four steps

1. **Discover.** `GET https://app.quanticdata.io/.well-known/oauth-authorization-server` → `agent_auth.register_uri` and `agent_auth.claim_uri`.
2. **Register.** Tell the user which service you are registering with, then:
   ```bash
   curl -X POST https://app.quanticdata.io/api/v1/agent/auth \
     -H 'Content-Type: application/json' \
     -d '{"method":"verified_email","email":"user@example.com","agent":{"name":"My agent","url":"https://example.com/agent"}}'
   ```
   `200 {"status":"pending","registration_type":"verified_email","claim_uri":"https://app.quanticdata.io/api/v1/agent/auth/claim","expires_in":600}` — a 6-digit code was emailed to that address. The response is the same whether or not an account already exists for that email. (`{"type":"service_auth","login_hint":"user@example.com"}` is accepted as an alias.)
3. **Ask the user for the code** (it is in their mailbox, subject "… is your QuanticData verification code — an AI agent asked to register"). The code expires in 10 minutes; 5 wrong codes cancel the registration.
4. **Claim.**
   ```bash
   curl -X POST https://app.quanticdata.io/api/v1/agent/auth/claim \
     -H 'Content-Type: application/json' \
     -d '{"email":"user@example.com","code":"123456"}'
   ```
   `200 {"credential_type":"api_key","api_key":"qd_live_…","key_prefix":"qd_live_abcd","account_status":"created","usage":{"header":"Authorization: Bearer <api_key>","api_base":"https://api.quanticdata.io/v1"},"docs":"https://quanticdata.io/docs/","auth_md":"https://quanticdata.io/auth.md"}` — the key is returned **once** and never emailed. `account_status` is `created` (new account, born verified, pay-as-you-go tier with the standard free monthly usage, no password: the person signs in later with a password-reset link) or `existing` (the email already had an account: a new key was added to it, nothing else changed). The person sees, rotates and revokes the key from `https://app.quanticdata.io/api-keys`.

**When the answer is not `pending`:**

| Status | `error` | What to do |
| --- | --- | --- |
| `400` | `invalid_request`, `anonymous_not_enabled` | Fix the body; only `verified_email` is offered. |
| `422` | `invalid_email` | Temporary or unreachable mailbox: use a permanent address. |
| `428` | `human_verification_required` | This registration needs a person: send the user to `register_human` (`https://app.quanticdata.io/register`), they create the account and a key in the dashboard and give you the key. Do not retry. |
| `429` | `rate_limited`, `too_many_attempts` | Honour `Retry-After`. Limits: 5 registrations per IP per hour, 20 per IP per day, 10 per email domain per day, 3 codes per email per hour, a global daily cap. |
| `410` | `claim_expired` | No pending registration or the code expired: start again at step 2. |
| `503` | `agent_registration_disabled` | Agent registration is switched off: use `register_human`. |

The `agent_auth` block as published:

```json
"agent_auth": {
  "skill": "https://quanticdata.io/auth.md",
  "register_uri": "https://app.quanticdata.io/api/v1/agent/auth",
  "identity_endpoint": "https://app.quanticdata.io/api/v1/agent/auth",
  "claim_uri": "https://app.quanticdata.io/api/v1/agent/auth/claim",
  "claim_endpoint": "https://app.quanticdata.io/api/v1/agent/auth/claim",
  "identity_types_supported": ["identity_assertion", "service_auth"],
  "identity_assertion": {
    "assertion_types_supported": ["verified_email"],
    "credential_types_supported": ["api_key"],
    "claim_uri": "https://app.quanticdata.io/api/v1/agent/auth/claim"
  },
  "service_auth": { "credential_types_supported": ["api_key"], "claim_uri": "https://app.quanticdata.io/api/v1/agent/auth/claim" },
  "credential_types_supported": ["api_key"]
}
```

What **is** also automated: registration of an **OAuth client** for the MCP server (section 4). That registers the software, not the user — a signed-in person still approves the connection.

## 3. Discover the authorization requirements

- **Data API:** a request without a valid key answers `401` with the JSON envelope `{"type":"error","message":"Missing or invalid Authorization header. Use: Authorization: Bearer YOUR_API_KEY"}`. There is no OAuth on the Data API: it is API keys only.
- **MCP server:** a request without a token answers `401` with
  `WWW-Authenticate: Bearer resource_metadata="https://api.quanticdata.io/.well-known/oauth-protected-resource/mcp", scope="mcp"`.
  Follow it: the protected resource metadata names the resource `https://api.quanticdata.io/mcp`, the scope `mcp`, bearer in the `Authorization` header, and the authorization server `https://app.quanticdata.io`; that server's metadata lives at `https://app.quanticdata.io/.well-known/oauth-authorization-server`.
- **Copies on this host:** `https://quanticdata.io/.well-known/oauth-protected-resource` is the same document as the MCP one (the marketing site itself is not a protected resource; it points you to the one that is). `https://quanticdata.io/.well-known/oauth-authorization-server` redirects to the issuer's own metadata, because the issuer is `https://app.quanticdata.io`, not `https://quanticdata.io`.

## 4. OAuth 2.1 for the MCP server

Everything below is read from the live authorization server metadata.

| Field | Value |
| --- | --- |
| `issuer` | `https://app.quanticdata.io` |
| `authorization_endpoint` | `https://app.quanticdata.io/oauth/authorize` |
| `token_endpoint` | `https://app.quanticdata.io/api/v1/oauth/token` |
| `registration_endpoint` | `https://app.quanticdata.io/api/v1/oauth/register` (RFC 7591 dynamic client registration) |
| `revocation_endpoint` | `https://app.quanticdata.io/api/v1/oauth/revoke` |
| `scopes_supported` | `mcp` (the only scope) |
| `grant_types_supported` | `authorization_code`, `refresh_token` |
| `response_types_supported` | `code` |
| `code_challenge_methods_supported` | `S256` (PKCE is required) |
| `token_endpoint_auth_methods_supported` | `none`, `client_secret_post`, `client_secret_basic` |
| `client_id_metadata_document_supported` | `true` |

**Client registration — two automated options, no human in this step:**

- *Dynamic Client Registration (RFC 7591):* `POST https://app.quanticdata.io/api/v1/oauth/register` with your client metadata (name, `redirect_uris`, …). Registration is open and rate-limited per source address; public clients may use `token_endpoint_auth_method: "none"`.
- *Client ID Metadata Documents:* use an HTTPS URL as `client_id`; the URL must serve a JSON document describing the client. It is fetched and cached for a day.

**Authorization:** send the user to `authorization_endpoint` with `response_type=code`, your `client_id`, `redirect_uri`, `scope=mcp`, a PKCE `code_challenge` (`S256`) and `resource=https://api.quanticdata.io/mcp` (RFC 8707 — the server uses it to pick the brand and rejects unknown resources with `invalid_target`). The user signs in to their QuanticData account and approves. The response carries `iss` (RFC 9207). Exchange the code at `token_endpoint` with the `code_verifier` and the same `resource`.

**Tokens:** opaque bearer tokens bound to that user's account and key; there is no `jwks_uri` because they are not JWTs and are validated server-side. Access tokens are short-lived (about an hour); use the `refresh_token` grant to renew. Revoke at `revocation_endpoint`; the user can also disconnect the client from the dashboard.

## 5. Use the credential

**Data API** — one header, nothing else is read (no `X-Api-Key`, never in the query string):

```http
GET /v1/scraper/usage HTTP/1.1
Host: api.quanticdata.io
Authorization: Bearer qd_live_YOUR_API_KEY
```

Every response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`. Failed calls are not billed.

**MCP server** — Streamable HTTP, JSON-RPC over `POST https://api.quanticdata.io/mcp`, with either the OAuth access token or the API key:

```http
POST /mcp HTTP/1.1
Host: api.quanticdata.io
Authorization: Bearer <access_token or qd_live_…>
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2025-06-18
```

Local alternative: `npx -y quanticdata-mcp` with the key in the environment (see `https://quanticdata.io/mcp-server/`).

**Proxies** — connect with the username/password shown for the plan; endpoints, ports and targeting syntax are documented per network at `https://quanticdata.io/docs/` and on each product page.

## 6. Errors

| Status | Meaning | What to do |
| --- | --- | --- |
| `401` | Missing, malformed, unknown, disabled or expired key / token, or inactive account | Get a valid credential (sections 2 and 4); for MCP, follow `WWW-Authenticate` |
| `402` | Free allowance plus balance cannot cover the call, or the monthly cap is reached; nothing was charged | A human tops up or raises the cap in the dashboard |
| `403` | Operation not allowed for this account | Stop; ask the account owner |
| `429` | Rate limit (per key, per plan, or pool capacity) | Back off for `Retry-After` seconds |
| `invalid_target` (OAuth) | `resource` is not `https://api.quanticdata.io/mcp` | Fix the resource indicator |

## 7. Revocation

- API keys: disabled or deleted by the owner at `https://app.quanticdata.io/api-keys`; a revoked key answers `401` immediately.
- OAuth tokens: `POST https://app.quanticdata.io/api/v1/oauth/revoke` (RFC 7009) with the access or refresh token; or the user removes the connection from the dashboard.

## 8. agent_auth (machine-readable summary)

The same block is published in the authorization server metadata (`https://app.quanticdata.io/.well-known/oauth-authorization-server`). Registration method offered: `verified_email` (section 2). No `anonymous` or `id-jag` method.

```json
{
  "agent_auth": {
    "skill": "https://quanticdata.io/auth.md",
    "register_uri": "https://app.quanticdata.io/api/v1/agent/auth",
    "identity_endpoint": "https://app.quanticdata.io/api/v1/agent/auth",
    "claim_uri": "https://app.quanticdata.io/api/v1/agent/auth/claim",
    "claim_endpoint": "https://app.quanticdata.io/api/v1/agent/auth/claim",
    "identity_types_supported": ["identity_assertion", "service_auth"],
    "identity_assertion": {
      "assertion_types_supported": ["verified_email"],
      "credential_types_supported": ["api_key"],
      "claim_uri": "https://app.quanticdata.io/api/v1/agent/auth/claim"
    },
    "service_auth": { "credential_types_supported": ["api_key"], "claim_uri": "https://app.quanticdata.io/api/v1/agent/auth/claim" },
    "credential_types_supported": ["api_key"],
    "oauth": {
          "issuer": "https://app.quanticdata.io",
          "resource": "https://api.quanticdata.io/mcp",
          "scopes": ["mcp"],
          "dynamic_client_registration": "https://app.quanticdata.io/api/v1/oauth/register",
          "client_id_metadata_document_supported": true
        }
  }
}
```

## 9. Links

- API reference: `https://quanticdata.io/docs/` · Markdown twin: `https://quanticdata.io/docs/index.md` · endpoint index: `https://quanticdata.io/docs/llms.txt`
- OpenAPI 3.0: `https://quanticdata.io/docs/openapi.json` · `https://quanticdata.io/docs/openapi.yaml`
- API catalog (RFC 9727): `https://quanticdata.io/.well-known/api-catalog`
- MCP server page: `https://quanticdata.io/mcp-server/` · endpoint `https://api.quanticdata.io/mcp` · health `https://api.quanticdata.io/v1/health`
- Protected resource metadata: `https://api.quanticdata.io/.well-known/oauth-protected-resource/mcp` · authorization server: `https://app.quanticdata.io/.well-known/oauth-authorization-server`
- Site index for agents: `https://quanticdata.io/llms.txt` · full text: `https://quanticdata.io/llms-full.txt`
- For agents, on one page: `https://quanticdata.io/for-agents/` · the registration above as a tutorial: `https://quanticdata.io/tutorials/agent-self-registration/` · buying a plan from the balance (UCP checkout): `https://quanticdata.io/tutorials/agent-buys-proxies/`
- Support: hello@quanticdata.io
