# auth.md — Altacee

You are an agent. Altacee is a software studio, and this service lets you **send a project brief on behalf of a user** — the same brief a human sends through https://altacee.com/start. It follows the anonymous profile of [agentic registration](https://github.com/workos/auth.md): discover → register → exchange for an access_token → post the brief. Follow the steps in order.

Before you post anything, the user must have asked you to contact Altacee, and the name and email you send must be theirs — Altacee replies to that address within 24 hours. Never invent contact details.

## Step 1 — Discover

You may already hold the 401 that sent you here; its `WWW-Authenticate` header carries the metadata URL. Otherwise fetch it directly:

```http
GET https://altacee.com/.well-known/oauth-protected-resource
```

```json
{
  "resource": "https://altacee.com/api/agent",
  "resource_name": "Altacee",
  "authorization_servers": ["https://altacee.com"],
  "scopes_supported": ["projects.write"],
  "bearer_methods_supported": ["header"]
}
```

Then the authorization server metadata:

```http
GET https://altacee.com/.well-known/oauth-authorization-server
```

```json
{
  "issuer": "https://altacee.com",
  "token_endpoint": "https://altacee.com/oauth2/token",
  "grant_types_supported": ["urn:ietf:params:oauth:grant-type:jwt-bearer"],
  "agent_auth": {
    "skill": "https://altacee.com/auth.md",
    "identity_endpoint": "https://altacee.com/agent/identity",
    "identity_types_supported": ["anonymous"]
  }
}
```

Use the URLs from these documents, not the ones hard-coded here.

## Step 2 — Register (anonymous)

Only `anonymous` is supported. No ID-JAG, no email ceremony.

```http
POST /agent/identity
Content-Type: application/json

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

Response (200):

```json
{
  "registration_id": "reg_...",
  "registration_type": "anonymous",
  "identity_assertion": "<service-signed JWT>",
  "assertion_expires": "2026-10-20T12:00:00.000Z",
  "pre_claim_scopes": ["projects.write"]
}
```

Keep `identity_assertion` in memory. It is valid for 24 hours. There is no claim ceremony and no `claim_token`.

## Step 3 — Exchange the assertion

```http
POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&assertion=<identity_assertion>
&resource=https://altacee.com/api/agent
```

Response (200):

```json
{
  "access_token": "<token>",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "projects.write"
}
```

`resource` is optional; if you send it, it must equal the `resource` from Step 1.

## Step 4 — Post the brief

```http
POST /api/agent/project
Authorization: Bearer <access_token>
Content-Type: application/json

{
  "name": "Ada Lovelace",
  "email": "ada@example.com",
  "scope": "web-development",
  "brief": "What they want built, for whom, by when, and any constraints."
}
```

| Field   | Rule                                                                                  |
| ------- | ------------------------------------------------------------------------------------- |
| `name`  | The user's name, 2–200 characters.                                                    |
| `email` | The user's email, where Altacee will reply.                                           |
| `scope` | Short project type, 1–100 characters (e.g. `web-development`, `ai-integration`).      |
| `brief` | 20–5000 characters. Goal, users, timeline, budget if known. Plain text.              |

Response (201): `{ "ok": true }`. The user gets an acknowledgement email; an engineer replies with a scoped plan within 24 hours. Tell the user that, and stop — one brief per request from the user.

To book a 15-minute call instead of (or as well as) sending a brief, use the same token with [book.md](https://altacee.com/book.md).

## Errors

| Code / status                        | Where                 | What to do                                                                 |
| ------------------------------------ | --------------------- | -------------------------------------------------------------------------- |
| `invalid_request` (400)              | `/agent/identity`     | Body must be exactly `{ "type": "anonymous" }`.                            |
| `issuer_not_enabled`, `service_auth_not_enabled` (400) | `/agent/identity` | Those methods are not offered. Use `anonymous`.                |
| `unsupported_grant_type` (400)       | `/oauth2/token`       | Use the jwt-bearer grant type exactly as in Step 3.                        |
| `invalid_target` (400)               | `/oauth2/token`       | Drop `resource` or send the value from Step 1.                             |
| `invalid_grant` (400)                | `/oauth2/token`       | Assertion expired or invalid. Restart at Step 2.                           |
| 401 `unauthorized`                   | `/api/agent/project`  | No token sent. Start at Step 1.                                            |
| 401 `invalid_token`                  | `/api/agent/project`  | Token expired. Re-run Step 3 once; if that fails, restart at Step 2.       |
| `invalid_request` (400)              | `/api/agent/project`  | A field broke a rule above; `error_description` says which. Fix and retry. |
| 429                                  | any                   | Wait `Retry-After` seconds. Do not loop.                                   |
| 502 / 503                            | any                   | Not your fault. Tell the user to email contact@altacee.com instead.        |

Do not retry a 4xx with the same payload.

## Revocation

There is no revocation endpoint. Access tokens expire after an hour and assertions after a day; Altacee can invalidate all of them at once. A 401 or `invalid_grant` on a flow that used to work means start again at Step 2.
