---
title: "Create a new API token"
method: POST
path: "/api/tokens"
tags: ["API Tokens"]
---

# Create a new API token

`POST /api/tokens`

## Request

- Base URL: `https://domani.run`
- URL: `https://domani.run/api/tokens`
- Auth: HTTP bearer

Creates a new API token. The full key is returned only in this response - store it securely. You can create multiple tokens to separate access for different applications.

## Request body

- object
  - `name` string: Human-readable name to identify this token
  - `expires_in` integer: Token lifetime in seconds (min 3600 = 1h, max 31536000 = 1y). Omit for no expiration.
  - `expires_at` string, date-time: Absolute expiration date (ISO 8601). Alternative to expires_in.
  - `scopes` string[]: Permission scopes for this token. Use ['*'] for full access (default). A token can only grant scopes it already has (scope attenuation). Scopes: domains:read (GET /api/domains, GET /api/domains/{domain}, GET /api/domains/{domain}/dns, /dnssec, /status, /email/check, /auth-code, /transfer-away, /transfer-status, /analytics), domains:write (PUT /api/domains/{domain}/dns, POST/DELETE /api/domains/{domain}/dnssec, POST /connect, POST /verify, PUT /settings, PUT /parking, PUT/DELETE /api/domains/{domain}/for-sale, POST /api/domains/import, POST /import/verify), domains:transfer (POST /api/domains/buy, POST /transfer, POST /renew (involves payment, includes marketplace purchases)), tokens:read (GET /api/tokens), tokens:write (POST /api/tokens, DELETE /api/tokens/{id}), webhooks:read (GET /api/webhooks, GET /api/webhooks/{id}/deliveries), webhooks:write (POST /api/webhooks, PATCH /api/webhooks/{id}, DELETE /api/webhooks/{id}), email:read (GET /api/emails, /api/emails/{address}, /api/emails/{address}/messages, /api/emails/{address}/aliases, /api/email/changes, /api/domains/{domain}/email/status, /api/domains/{domain}/email/deliverability, /api/suppressions, GET /api/contacts), email:write (POST /api/emails, POST /api/emails/{address}/send, POST /api/domains/{domain}/email/setup, aliases + catch-all, POST/DELETE /api/suppressions, POST/DELETE /api/contacts), email:delete (Permanently delete messages already in Trash. Moving messages to Trash only requires email:write. Grant this scope only to agents allowed to irreversibly erase email content), email:manage_mailboxes (Create mailboxes (POST /api/emails) and nothing else. The narrow admin scope for agents that may spin up addresses for new projects (partners@, launch@) without being able to read or send mail, manage domains, or touch tokens), email:auth_secrets (Read messages classified as authentication mail (OTP / verification codes, password resets, magic links). Without it, email:read still lists them but subject and body come back redacted - so a stolen agent token can't harvest 2FA codes. Grant it only to agents that genuinely need to complete logins), account:read (GET /api/me, GET /api/agents/identity), account:write (DELETE /api/me, POST /api/billing/setup, POST /api/billing/subscribe, POST /api/billing/cancel, POST /api/me/resend-verification, POST/PATCH/DELETE /api/agents/identity), billing:read (GET /api/billing/invoices), search (GET /api/domains/search, /suggest, /whois, /dns-check, GET /api/tlds), deals:read (GET /api/deals, GET /api/deals/{id}), deals:write (POST /api/domains/sell, PATCH /api/deals/{id}), notifications:read (GET /api/notifications, GET /api/notifications/count), backorders:read (GET /api/backorders, GET /api/backorders/{id}), backorders:write (POST /api/backorders, DELETE /api/backorders/{id}), assistant:read (Read Mailzero assistant settings, the Today queue, Work items, exact action previews, history-import progress, and content-minimized Activity), assistant:write (Change Mailzero assistant settings, record consent and start history imports, record human Decisions on Work items, retry imports, and export or delete derived assistant data. Never sends mail).
  - `max_per_tx` number: Per-transaction spend cap in USD. Any single charge above this fails with 403 SPEND_CAP_EXCEEDED. A token can only grant caps at or below its own (CAP_ESCALATION otherwise).
  - `max_per_month` number: Rolling calendar-month spend cap in USD across all paid operations made with this token.
  - `agent_identity_id` string: Optional id of an agent identity owned by this account. Mail actions made with the token are attributed to that agent.
  - `http_route_policy` object: Required structured authority for a scoped token with http-routes:read or http-routes:write.
    - `hostname_rules` union[], required
      - union
        - object
          - `domain` string, required
          - `kind` 'exact', required
          - `hostname` string, required
        - object
          - `domain` string, required
          - `kind` 'subdomain_prefix', required
          - `prefix` string, required
    - `max_concurrent` integer
    - `max_lease_seconds` integer
    - `acknowledge_apex_delegation` boolean
  - `mailboxes` string[]: Confine the token to these mailbox addresses (slug@domain). A confined token only sees and acts on those mailboxes; a confined caller can only delegate a subset of its own (400 MAILBOX_ESCALATION otherwise).

## Response `201`

Token created - save the key, it won't be shown again

- object
  - `id` string
  - `name` string
  - `key` string: Full API key - save this, it won't be shown again
  - `expiresAt` string, date-time, nullable: When this token expires (null = never)
  - `scopes` string[]: Permission scopes granted to this token
  - `createdAt` string, date-time
  - `max_per_tx` number, nullable: Per-transaction spend cap in USD (null = uncapped)
  - `max_per_month` number, nullable: Monthly spend cap in USD (null = uncapped)
  - `mailbox_ids` string[]: Mailbox ids this token is confined to
  - `http_route_policy` HttpRoutePolicy, nullable: Structured hostname, concurrency, and lease authority for a least-privilege HTTP route token.
    - `hostname_rules` union[], required
      - union
        - object
          - `domain` string, required
          - `kind` 'exact', required
          - `hostname` string, required
        - object
          - `domain` string, required
          - `kind` 'subdomain_prefix', required
          - `prefix` string, required
    - `max_concurrent` integer, required
    - `max_lease_seconds` integer, required
  - `agent_identity` object, nullable
    - `id` string
    - `name` string, nullable
    - `slug` string

## Other responses

- `400`: Token or HTTP route policy input is invalid
- `401`: Missing or invalid API key
- `403`: Token lacks required scope
- `409`: HTTP route policy requires an explicit apex delegation acknowledgement
- `429`: Rate limit exceeded - wait and retry

---

[API](https://skmtc.dev/domani/apis/domani-run-api.md) · [All operations](https://skmtc.dev/domani/apis/domani-run-api/llms.txt) · [OpenAPI document](https://skmtc.dev/domani/apis/domani-run-api/revisions/7679f8159533?raw)
