# GTM Tools — auth.md

This service implements the [auth.md](https://workos.com/auth-md) agent-registration protocol.
You (an autonomous agent) can register and obtain an API key without a human filling out a form.

## Step 1 — Discover

Fetch this service's authorization-server metadata:

```http
GET https://api.gtm-tools.sh/.well-known/oauth-authorization-server
```

The response includes an `agent_auth` block with the endpoints below.

## Step 2 — Pick a method

This service supports two registration shapes:

| `type` | `assertion_type` | When to use |
|---|---|---|
| `anonymous` | — | You have no user context. You get a working API key immediately; the user can claim it later via email. |
| `identity_assertion` | `verified_email` | You know the user's email. They confirm a 6-digit code; you get an API key bound to their workspace. |

`identity_assertion` with `urn:ietf:params:oauth:token-type:id-jag` (agent-provider delegation grants) is **not yet supported**.

## Step 3 — Register

```http
POST https://api.gtm-tools.sh/agent/identity
Content-Type: application/json
```

**Anonymous shape:**

```json
{ "type": "anonymous" }
```

Response (200):

```json
{
  "access_token": "sk_…",
  "token_type": "bearer",
  "expires_in": 31536000,
  "scope": "api"
}
```

The `access_token` is a long-lived API key — use it directly in `Authorization: Bearer …` against `https://api.gtm-tools.sh/mcp` or `https://api.gtm-tools.sh/api/v0/{tool_name}`. Revoke via `POST https://api.gtm-tools.sh/oauth/revoke`.

**Verified-email shape:**

```json
{
  "type": "identity_assertion",
  "assertion_type": "verified_email",
  "assertion": "user@example.com"
}
```

Response (200) — the service has emailed the user a 6-digit code; proceed to Step 4:

```json
{
  "claim_token": "clm_…",
  "expires_in": 600,
  "interval": 2,
  "verification_uri": "https://api.gtm-tools.sh/agent/identity/claim",
  "user_code_length": 6
}
```

## Step 4 — Claim ceremony

The user receives the 6-digit code by email and reads it to you. You submit it on their behalf:

```http
POST https://api.gtm-tools.sh/agent/identity/claim
Content-Type: application/json
```

```json
{ "claim_token": "clm_…", "user_code": "123456" }
```

The code is single-shot. Once accepted, the claim is bound and you can exchange it in Step 5. If the user hasn't read the code to you yet, skip ahead and poll Step 5 directly — it'll return `authorization_pending` until the code arrives.

## Step 5 — Exchange the claim for an access token

```http
POST https://api.gtm-tools.sh/oauth/token
Content-Type: application/x-www-form-urlencoded

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

While the user hasn't entered the code yet:

```json
{ "error": "authorization_pending" }
```

After the code is accepted (Step 4):

```json
{
  "access_token": "sk_…",
  "token_type": "bearer",
  "expires_in": 31536000,
  "scope": "api"
}
```

## Step 6 — Use the access token

```http
GET https://api.gtm-tools.sh/api/v0/get_token_balance
Authorization: Bearer sk_…
```

All MCP and REST endpoints accept the same key. Free tools (cost `0`) work immediately; paid tools require a token balance — top up via the `buy_tokens` MCP tool or the dashboard.

## Errors

| HTTP | `error` | Meaning |
|---|---|---|
| 400 | `invalid_request` | Missing or malformed field |
| 400 | `unsupported_grant_type` | We don't accept that `grant_type` |
| 400 | `invalid_claim_token` | `claim_token` unknown or expired |
| 400 | `claim_expired` | The 10-minute window elapsed; restart from Step 3 |
| 400 | `invalid_grant` | Generic catch-all for code-exchange failures |
| 401 | `authorization_pending` | User hasn't read back the code yet — keep polling |
| 401 | `anonymous_not_enabled` | (n/a — anonymous is enabled) |

## Revocation

```http
POST https://api.gtm-tools.sh/oauth/revoke
Content-Type: application/x-www-form-urlencoded

token=sk_…&token_type_hint=access_token
```

Returns 200 on success (per RFC 7009; same response whether or not the token existed).
