# Agents

The Agents API lets an AI agent provision a brand new Cosmic project and bucket on behalf of a human, without the human needing a Cosmic account up-front. The bucket starts in a restricted "unclaimed" state, an OTP is emailed to the human, and the agent can hand the code back to lift the limits.

This is the underlying API used by the [Agent Signup](/docs/agent-skills#agent-signup) flow exposed in the CLI and the MCP `/v1/agent` scope.

### Base URL
```
https://dapi.cosmicjs.com

```
Unlike the bucket-scoped endpoints in the rest of this reference, the Agents endpoints live on the dashboard API (`dapi.cosmicjs.com`).

---

## Sign up 

Provision a new project + bucket and trigger a claim email to `human_email`.

This endpoint does **not** require authentication. The request must be sent as JSON with `Content-Type: application/json`. Re-calling with the same `human_email` + `agent_id` is idempotent: it refreshes the OTP and returns the existing project rather than creating a new one.

### Required body

The human's email address. The 6-digit OTP and a claim URL are sent here. Must be a valid email and not already a human-owned Cosmic account (see [errors](#errors)).

Display name for the new Cosmic project. The bucket slug is derived from this.

Stable identifier for the calling agent (e.g. `cursor`, `claude-code`, your-internal-agent slug). Used for rate limiting and analytics. Plain string, 1-128 chars.

### Optional body

Free-form label for the surface the agent runs in (e.g. `desktop`, `cli`, `mcp`). Echoed back in `/v3/agents/status`.

### Response

Bearer token (prefix `agk_`) used to call [`/v3/agents/verify`](#verify) and [`/v3/agents/status`](#status). Persist this securely; it is the durable agent-flow credential and survives token rotation.

User-scoped JWT for the shadow user that owns the new project + bucket. Pass it as `Authorization: Bearer ` to call any standard [Dashboard API](/docs/api) endpoint (object types, webhooks, team, etc.) on the agent's project. Valid for **14 days** while unclaimed (matches the auto-delete window). Auto-revoked when the human claims the bucket (the shadow user's `status` flips to 0). For long-lived agents, hit [`/v3/agents/status`](#status) periodically to obtain a fresh token.

Always `unclaimed` on a fresh sign-up.

`{ id, name }` for the provisioned project.

`{ slug, read_key, write_key }`. Use these immediately with the standard [bucket API](/docs/api/objects) and [SDK](https://www.npmjs.com/package/@cosmicjs/sdk). The keys returned here are raw (not JWT-wrapped) and ready to drop into `createBucketClient`. Bucket keys are durable and survive claim.

URL the agent can hand the human as an alternative to the OTP. Visiting it on `app.cosmicjs.com` lets the human verify and take ownership in one step.

Restricted-mode quotas, see [Auth states & limits](#auth-states-and-limits).

Number of days until the project is hard-deleted if it has not been claimed. Currently `14`.
```bash {{ title: 'cURL' }}
curl -X POST https://dapi.cosmicjs.com/v3/agents/sign-up \
  -H "Content-Type: application/json" \
  -d '{
    "human_email": "tony@example.com",
    "project_name": "Recipe Blog",
    "agent_id": "my-agent-platform"
  }'

```
```js {{ title: 'JavaScript' }}
const res = await fetch('https://dapi.cosmicjs.com/v3/agents/sign-up', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    human_email: 'tony@example.com',
    project_name: 'Recipe Blog',
    agent_id: 'my-agent-platform',
  }),
});
const { agent_key, bucket } = await res.json();
```

```json {{ title: '200 OK' }}
{
  "message": "Agent signup created. OTP sent to human_email.",
  "auth_type": "unclaimed",
  "agent_key": "agk_...",
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "project": { "id": "...", "name": "Recipe Blog" },
  "bucket": {
    "slug": "recipe-blog-...",
    "read_key": "...",
    "write_key": "..."
  },
  "claim_url": "https://app.cosmicjs.com/claim?token=agk_...",
  "limits": {
    "ai_credits_remaining": 0,
    "media_mb_total": 5,
    "objects_max": 50
  },
  "auto_delete_after_days": 14
}
```
---

## Verify 

Submit the 6-digit code from the claim email to lift restricted-mode limits.

Requires `Authorization: Bearer agk_...` from the sign-up response. The agent never sees the code itself; the human reads it from their email and pastes it back.

### Required body

The 6-digit numeric OTP from the claim email. The code expires; if expired, call [`/v3/agents/sign-up`](#sign-up) again with the same `human_email` + `agent_id` to issue a fresh one (idempotent).

### Response

`verified` on success.

`verified`.

A freshly issued user JWT, with a longer expiry now that the project is verified (`90d`). Replace any previously stored token with this one.

`null` once verified; the bucket is on standard free-tier limits.

```bash {{ title: 'cURL' }}
curl -X POST https://dapi.cosmicjs.com/v3/agents/verify \
  -H "Authorization: Bearer agk_..." \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'
```
```js {{ title: 'JavaScript' }}
await fetch('https://dapi.cosmicjs.com/v3/agents/verify', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${agent_key}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ code: '123456' }),
});
```

```json {{ title: '200 OK' }}
{
  "message": "Verified. Restricted-mode limits lifted.",
  "auth_type": "verified",
  "claim_status": "verified",
  "limits": null
}
```
---

## Status 

Check the current claim state and remaining limits for the agent's project + bucket. Safe to poll while waiting for the human to verify.

Requires `Authorization: Bearer agk_...`. Also useful as a recovery path: if the agent lost the sign-up response (e.g. CLI re-login on a new machine), `/status` returns the bucket slug, read key, and write key.

### Response

`unclaimed` or `verified`.

`unclaimed`, `verified`, or `human_owned` (the human signed up at `app.cosmicjs.com` with the same email and absorbed the project).

`agent_unclaimed` while restricted, otherwise the project's normal plan id.

A freshly issued user JWT for the shadow user. Treat `/status` as the canonical refresh endpoint: call it periodically with the `agent_key` to rotate the token before it expires.

Restricted-mode limits while unclaimed, `null` once verified or claimed.

Days until hard-delete if unclaimed; `null` once claimed.

`{ id, name }`.

`{ slug, read_key, write_key }`. Keys are raw (not JWT-wrapped).

The email the agent signed up against.

Echoed back from sign-up.

```bash {{ title: 'cURL' }}
curl https://dapi.cosmicjs.com/v3/agents/status \
  -H "Authorization: Bearer agk_..."
```
```json {{ title: '200 OK (unclaimed)' }}
{
  "auth_type": "unclaimed",
  "claim_status": "unclaimed",
  "plan_id": "agent_unclaimed",
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "limits": {
    "ai_credits_remaining": 0,
    "media_mb_total": 5,
    "objects_max": 50
  },
  "auto_delete_after_days": 14,
  "project": { "id": "...", "name": "Recipe Blog" },
  "bucket": {
    "slug": "recipe-blog-...",
    "read_key": "...",
    "write_key": "..."
  },
  "human_email": "tony@example.com",
  "agent_id": "my-agent-platform",
  "client": "cli"
}
```

---

## Auth states and limits

An agent-created project moves through three states:

| State | What it means | What's allowed |
|---|---|---|
| `unclaimed` | Bucket created by agent, human has not verified yet | Create/read/update up to **50 objects**, up to **5 MB** total media. **AI generation is disabled.** |
| `verified` | Human passed the OTP back to the agent (or visited the claim URL) | Standard free-tier limits, including AI generation |
| `human_owned` | Human took ownership by signing up at `app.cosmicjs.com` with the same email | Standard free-tier limits, full dashboard access |

Calls that exceed restricted-mode quotas return `402` with `code: "agent_unclaimed_limit"` and the offending `action` (`ai_generate`, `object_create`, or `media_upload`). Use this signal to prompt the human to claim:

```json {{ title: '402 Payment Required' }}
{
  "message": "AI generation is disabled on unclaimed agent buckets. Ask the human to claim this bucket to enable AI features.",
  "code": "agent_unclaimed_limit",
  "action": "ai_generate",
  "limits": {
    "ai_credits_remaining": 0,
    "media_mb_total": 5,
    "objects_max": 50
  }
}

```
Unclaimed projects are hard-deleted after **14 days** if not claimed. Plan accordingly: prompt the human early, and persist the `agent_key` so a returning user can resume the claim flow.

---

## Errors

| Status | `code` | When |
|---|---|---|
| `400` | (none) | Missing/invalid body or expired/incorrect OTP on `/verify`. |
| `401` | (none) | Missing or invalid `Authorization: Bearer agk_...` on `/verify` or `/status`. |
| `402` | `agent_unclaimed_limit` | Caller exceeded restricted-mode quotas (returned by the bucket data plane, not by this API). |
| `409` | `user_already_exists` | `human_email` already belongs to a Cosmic user. Response includes a `claim_existing_url` pointing the human to `/login?email=...`. Do not retry with a different email; ask the human to log in and provision a bucket from the dashboard. |
| `429` | (none) | Rate limit. The `/sign-up` endpoint is capped per IP, and `agent_id` has a daily ceiling. Back off and retry. |

### Related

- [Agent Signup overview](/docs/agent-skills#agent-signup) - end-to-end flow, including CLI and MCP.

- [Authentication](/docs/api/authentication#agent-key) - where `agent_key` fits among other auth methods.

- [CLI: `cosmic agent-signup`](/docs/cli) - the same flow without writing fetch calls.
- [MCP server: agent scope](/docs/mcp-server#agent-scope) - the same flow exposed as MCP tools.