Domani Authentication API

The Authentication API from Domani — 5 operation(s) for authentication.

Operations 5

POST /api/auth/register Create a new account #
POST /api/auth/login Send a magic link sign-in email #
POST /api/auth/handoff Mint a one-time cross-host sign-in code #
POST /api/auth/handoff/redeem Redeem a one-time cross-host sign-in code #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/domani-run:domani-run-authentication-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

domani-run-authentication-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: domani.run Authentication API
  version: 1.0.0
  description: 'Domain infrastructure for AI agents. One API to search, register, and connect domain names.


    ## Authentication


    All authenticated endpoints require a Bearer token:


    ```

    Authorization: Bearer domani_sk_xxx

    ```


    Get your API key by registering:


    ```bash

    curl -X POST https://domani.run/api/auth/register \

    -H "Content-Type: application/json" \

    -d ''{"email": "you@example.com"}''

    ```


    ## Rate Limits


    Every response includes `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset` headers. When rate limited (HTTP 429), check the `Retry-After` header for seconds to wait.


    ## Error Handling


    All errors return a consistent JSON envelope with `error`, `code`, `hint`, and `documentation_url` fields. Use the `code` field for programmatic handling and the `hint` field for recovery guidance.


    ## MCP Server


    A real-time MCP (Model Context Protocol) server is available at `POST /mcp` using Streamable HTTP transport. Connect any MCP-compatible agent (Claude Code, Cursor, etc.) with your Bearer token for typed tool access (search, buy, DNS, etc.).


    ## Pagination


    The `GET /api/tlds` endpoint supports `limit` and `offset` query parameters. When paginated, the response includes a `Link` header with `rel="next"` for the next page.'
  contact:
    name: domani.run
    url: https://domani.run
servers:
- url: https://domani.run
  description: Production
security:
- BearerAuth: []
tags:
- name: Authentication
paths:
  /api/auth/register:
    post:
      operationId: registerUser
      summary: Create a new account
      description: Starts creating a new account (or signs an existing one in) by emailing a sign-in link; no API key is returned here. A person clicking that link in a browser lands on the dashboard already signed in. A CLI or agent without a browser session should use the device-login flow instead (`POST /api/auth/cli` then poll `GET /api/auth/cli/poll`), which emails the same approval and hands back an API key once approved - the response's `next_steps` says so. Pass a `ref` code to permanently link the new user to a referrer - the referrer earns a commission on all future domain purchases by this user.
      tags:
      - Authentication
      security: []
      x-rateLimit:
        limit: 5
        window: 1 minute
        scope: IP address
      x-codeSamples:
      - lang: bash
        label: cURL
        source: "curl -X POST https://domani.run/api/auth/register \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\": \"dev@example.com\"}'"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  example: dev@example.com
                ref:
                  type: string
                  description: Referral code - permanently links this user to the referrer. The referrer earns a commission on every domain purchase.
                  example: x7k9m2
              required:
              - email
            example:
              email: dev@example.com
              ref: x7k9m2
      responses:
        '202':
          description: Email verification started - no API key yet. If the account already existed, the same sign-in link is sent instead of an error.
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  verification_required:
                    type: boolean
                  message:
                    type: string
                  hint:
                    type: string
                  next_steps:
                    type: array
                    items:
                      type: string
                required:
                - ok
                - verification_required
                - message
                - hint
                - next_steps
              example:
                ok: true
                verification_required: true
                message: Check your email for a sign-in link to finish creating your account.
                hint: A human must open that email and click the link in a browser to finish verification; no API key is issued yet.
                next_steps:
                - 'If a person can click the email link, nothing else to do: they land on the dashboard already signed in.'
                - 'If you are a CLI or agent without a browser session, start a device-login flow instead: POST /api/auth/cli, then poll GET /api/auth/cli/poll?code=... until status is "complete" - the same email approves it and hands back an API key, no browser needed on your side.'
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Email is required
                code: MISSING_PARAMETER
                hint: Provide an 'email' field in the request body
                documentation_url: https://domani.run/llms.txt
        '429':
          description: Rate limit exceeded - wait and retry
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: integer
              example: 30
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Rate limit exceeded
                code: RATE_LIMIT_EXCEEDED
                hint: Wait 30 seconds before retrying
                retry_after: 30
                documentation_url: https://domani.run/llms.txt
  /api/auth/login:
    post:
      operationId: loginUser
      summary: Send a magic link sign-in email
      description: Sends a sign-in link to the provided email. If the user doesn't exist, creates an account first. The magic link redirects to the dashboard with auth credentials. For programmatic API access, use POST /api/auth/register to get an API key directly.
      tags:
      - Authentication
      security: []
      x-rateLimit:
        limit: 10
        window: 1 minute
        scope: IP address
      x-codeSamples:
      - lang: bash
        label: cURL
        source: "curl -X POST https://domani.run/api/auth/login \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"email\": \"dev@example.com\"}'"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
              required:
              - email
            example:
              email: dev@example.com
      responses:
        '200':
          description: Magic link sent - check your email
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  message:
                    type: string
              example:
                ok: true
                message: Check your email for a sign-in link.
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Email is required
                code: MISSING_PARAMETER
                hint: Provide an 'email' field in the request body
                documentation_url: https://domani.run/llms.txt
        '429':
          description: Rate limit exceeded - wait and retry
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: integer
              example: 30
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Rate limit exceeded
                code: RATE_LIMIT_EXCEEDED
                hint: Wait 30 seconds before retrying
                retry_after: 30
                documentation_url: https://domani.run/llms.txt
  /api/auth/verify:
    get:
      operationId: verifyMagicLink
      summary: Verify a magic link token
      description: Validates the magic link token and redirects to the dashboard with auth credentials. Used by the magic link email - not typically called by agents directly. Agents should use POST /api/auth/register instead.
      tags:
      - Authentication
      security: []
      parameters:
      - name: token
        in: query
        required: true
        schema:
          type: string
        description: Magic link token from email (base64url-encoded)
      responses:
        '307':
          description: Redirect to dashboard with auth credentials in query parameters
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Token is required
                code: MISSING_PARAMETER
                hint: Include the 'token' query parameter
                documentation_url: https://domani.run/llms.txt
  /api/auth/handoff:
    post:
      operationId: createAuthHandoff
      summary: Mint a one-time cross-host sign-in code
      description: 'Browser-only: lets a signed-in person on domani.run or mailzero.run resume their session on the other host without a second magic link. Returns a URL whose fragment carries a 60-second, single-use, host-bound code; the code is never logged or sent in a query string. Not useful outside a browser session, so it is not exposed as an agent tool.'
      tags:
      - Authentication
      x-rateLimit:
        limit: 10
        window: 1 minute
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                target:
                  type: string
                  enum:
                  - mail
                  - domani
                path:
                  type: string
              required:
              - target
              - path
            example:
              target: mail
              path: /inbox
      responses:
        '200':
          description: One-time handoff URL
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
          content:
            application/json:
              schema:
                type: object
                properties:
                  url:
                    type: string
              example:
                url: https://mailzero.run/auth/handoff#code=xxx&next=%2Finbox
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Invalid destination path
                code: INVALID_PARAMETER
                hint: Use a same-product path beginning with a single slash
                documentation_url: https://domani.run/llms.txt
        '401':
          description: Missing or invalid API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                missing:
                  summary: No Authorization header
                  value:
                    error: Missing API key
                    code: MISSING_API_KEY
                    hint: 'Include ''Authorization: Bearer domani_sk_xxx'' header'
                    documentation_url: https://domani.run/llms.txt
                invalid:
                  summary: Invalid or revoked key
                  value:
                    error: Invalid API key
                    code: INVALID_API_KEY
                    hint: Check your API key or create a new one at POST /api/tokens
                    documentation_url: https://domani.run/llms.txt
                expired:
                  summary: Token has expired
                  value:
                    error: API key has expired
                    code: EXPIRED_API_KEY
                    hint: Create a new token via POST /api/tokens or run 'domani login'
                    documentation_url: https://domani.run/llms.txt
        '429':
          description: Rate limit exceeded - wait and retry
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: integer
              example: 30
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Rate limit exceeded
                code: RATE_LIMIT_EXCEEDED
                hint: Wait 30 seconds before retrying
                retry_after: 30
                documentation_url: https://domani.run/llms.txt
  /api/auth/handoff/redeem:
    post:
      operationId: redeemAuthHandoff
      summary: Redeem a one-time cross-host sign-in code
      description: 'Browser-only: called by the /auth/handoff page on the target host to exchange the code from the URL fragment for a session, exactly like GET /api/auth/verify does for a magic link. The code must match the Host this request arrived on. Not an agent tool.'
      tags:
      - Authentication
      security: []
      x-rateLimit:
        limit: 20
        window: 1 minute
        scope: IP address
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                code:
                  type: string
              required:
              - code
            example:
              code: xxx
      responses:
        '200':
          description: Signed in - sets the short-lived session cookie GET /api/auth/session reads
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  next:
                    type: string
              example:
                ok: true
                next: /inbox
        '401':
          description: The code is missing, expired, used, or was issued for a different host
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  code:
                    type: string
                  hint:
                    type: string
                  documentation_url:
                    type: string
              example:
                error: This sign-in link is invalid or has expired.
                code: INVALID_HANDOFF
                hint: Go back and try again, or sign in with a new link.
                documentation_url: https://domani.run/docs#errors
        '429':
          description: Rate limit exceeded - wait and retry
          headers:
            X-RateLimit-Limit:
              description: Maximum requests allowed in the current window
              schema:
                type: integer
              example: 60
            X-RateLimit-Remaining:
              description: Requests remaining in the current window
              schema:
                type: integer
              example: 57
            X-RateLimit-Reset:
              description: Unix timestamp (seconds) when the window resets
              schema:
                type: integer
              example: 1700000000
            Retry-After:
              description: Seconds to wait before retrying
              schema:
                type: integer
              example: 30
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              example:
                error: Rate limit exceeded
                code: RATE_LIMIT_EXCEEDED
                hint: Wait 30 seconds before retrying
                retry_after: 30
                documentation_url: https://domani.run/llms.txt
components:
  schemas:
    Error:
      type: object
      properties:
        error:
          type: string
          description: Human-readable error message
        code:
          type: string
          description: Machine-readable error code
          enum:
          - MISSING_API_KEY
          - INVALID_API_KEY
          - EXPIRED_API_KEY
          - MISSING_PARAMETER
          - INVALID_DOMAIN
          - PAYMENT_REQUIRED
          - DOMAIN_UNAVAILABLE
          - RATE_LIMIT_EXCEEDED
          - USER_EXISTS
          - NOT_FOUND
          - UNKNOWN_PROVIDER
          - UNKNOWN_METHOD
          - TARGET_REQUIRED
          - INVALID_PARAMETER
          - CONTACT_REQUIRED
          - INVALID_CONTACT
          - INSUFFICIENT_SCOPE
          - SCOPE_ESCALATION
          - MAILBOX_CONFINED
          - CONFIRMATION_REQUIRED
          - OWN_SENDER
          - INVALID_SENDER_RULE
          - SENDER_RULE_NOT_FOUND
          - SENDER_RULE_LIMIT
          - SENDER_RULES_UNAVAILABLE
          - INVALID_KIND
          - MAIL_KIND_OFF
          - UNSUBSCRIBE_UNAVAILABLE
          - UNSUBSCRIBE_FAILED
          - DOMAIN_EXISTS
          - DOMAIN_NOT_ACTIVE
          - UNSUPPORTED_TLD
          - TLD_NOT_IN_PUBLIC_DNS
          - REGISTRANT_NOT_ELIGIBLE
          - NOT_AVAILABLE
          - ALREADY_REGISTERED
          - TRANSFER_NOT_ELIGIBLE
          - RENEWAL_NOT_ELIGIBLE
          - ALREADY_LISTED
          - LISTING_SOLD
          - SELF_PURCHASE
          - DESCRIPTION_TOO_LONG
          - DEAL_NOT_FOUND
          - INVALID_DEAL_STATE
          - EPP_ATTEMPTS_EXCEEDED
          - ACTIVE_DEAL_EXISTS
          - AGENT_IDENTITY_NOT_FOUND
          - AGENT_IDENTITY_ESCALATION
          - AGENT_MAILBOXES_REQUIRED
          - CREDENTIAL_REVOKE_FAILED
          - INVALID_IDEMPOTENCY_KEY
          - IDEMPOTENCY_KEY_MISMATCH
          - IDEMPOTENCY_KEY_REUSED
          - OPERATION_IN_PROGRESS
          - OPERATION_SUPERSEDED
          - INVALID_OPERATION_RECEIPT
          - WORKSPACE_ADMIN_REQUIRED
          - WORKSPACE_OWNER_REQUIRED
          - PRINCIPAL_NOT_IN_WORKSPACE
          - MAILBOX_NOT_IN_WORKSPACE
          - GROUP_NOT_IN_WORKSPACE
          - COLLECTION_NOT_IN_WORKSPACE
          - ACCESS_VERSION_CONFLICT
          - ACCESS_OFFER_INVALID
          - ACCESS_OFFER_EMAIL_MISMATCH
          - MAIL_DOMAIN_CAPACITY_EXHAUSTED
          - MAIL_PROVIDER_ERROR
          - INVALID_HTTP_ROUTE_HOSTNAME
          - INVALID_HTTP_ROUTE_UPSTREAM
          - INVALID_HTTP_ROUTE_UPSTREAM_HEADERS
          - INVALID_HTTP_ROUTE_LEASE
          - INVALID_HTTP_ROUTE_POLICY
          - INVALID_HOSTNAME_BINDING
          - HTTP_ROUTE_HOSTNAME_NOT_ALLOWED
          - HTTP_ROUTE_HOSTNAME_REQUIRED
          - HTTP_ROUTE_HOSTNAME_RESERVED
          - HTTP_ROUTE_HOSTNAME_UNAVAILABLE
          - HTTP_ROUTE_CONCURRENCY_LIMIT
          - HTTP_ROUTE_WORKSPACE_LIMIT
          - HTTP_ROUTE_DOMAIN_NOT_OWNED
          - HTTP_ROUTE_TERMINAL
          - HTTP_ROUTE_VERIFICATION_NOT_ENABLED
          - HTTP_ROUTE_VERIFICATION_REQUIRES_HTTPS
          - HTTP_ROUTE_POLICY_WITHOUT_SCOPE
          - HTTP_ROUTE_POLICY_REQUIRED
          - HTTP_ROUTE_AGENT_IDENTITY_REQUIRED
          - HTTP_ROUTE_POLICY_ESCALATION
          - HOSTNAME_BINDING_NOT_ACTIVE
          - HOSTNAME_BINDING_DNS_CONFLICT
          - HOSTNAME_BINDING_ACK_REQUIRED
          - HOSTNAME_BINDING_BROWSER_MODE_MISMATCH
          - HOSTNAME_DNS_CONFLICT
          - ZONE_READ_FAILED
          - DNS_VERSION_CONFLICT
          - UNAUTHORIZED
          - APEX_WEB_MODE_CONFLICT
          - APEX_DELEGATION_ACK_REQUIRED
          - VERIFICATION_COOLDOWN
          - VERIFICATION_SEND_FAILED
          - UPGRADE_REQUIRED
          - FREE_LIMIT_EXCEEDED
        upgrade_plan:
          type: object
          nullable: true
          description: 'On UPGRADE_REQUIRED / FREE_LIMIT_EXCEEDED: the cheapest plan that would give room for another mailbox, named from the catalog of the host the request came in on (Mailzero''s own plan on the mail host, Domani''s elsewhere). null when no plan in that catalog has more room.'
          properties:
            key:
              type: string
            name:
              type: string
            priceUsd:
              type: number
            mailboxes:
              type: integer
              nullable: true
        plan_limit:
          type: integer
          nullable: true
          description: 'On UPGRADE_REQUIRED / FREE_LIMIT_EXCEEDED: the current plan''s own mailbox limit (0 when the plan includes none, null when unlimited), so callers can tell a plan without mailboxes from a plan whose mailboxes are all in use.'
        hint:
          type: string
          description: Actionable recovery guidance for the caller
        fix_command:
          type: string
          description: CLI command to resolve the error (e.g. 'domani login', 'domani billing'). Present in CLI --json output.
        documentation_url:
          type: string
          format: uri
          description: Link to relevant documentation
        setup_url:
          type: string
          format: uri
          description: URL to resolve the issue (e.g. add payment method)
        fix_url:
          type: string
          format: uri
          description: URL to resolve the issue (alias for setup_url in CLI --json output)
        retry_after:
          type: integer
          description: Seconds until retry is allowed (present on 429 responses)
        retry_after_minutes:
          type: integer
          description: Minutes until another verification email may be requested
        retryable:
          type: boolean
          description: Whether retrying after the external condition changes is safe
      required:
      - error
      - code
      - documentation_url
      example:
        error: Missing API key
        code: MISSING_API_KEY
        hint: 'Include ''Authorization: Bearer domani_sk_xxx'' header'
        documentation_url: https://domani.run/llms.txt
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: domani_sk_xxx
      description: 'API key obtained by signing in (POST /api/auth/register starts email verification; a CLI or agent gets the key itself via the device-login flow, POST /api/auth/cli then GET /api/auth/cli/poll). Include as: `Authorization: Bearer domani_sk_xxx`. Keys use the prefix `domani_sk_` followed by 32 random characters.'
externalDocs:
  description: Interactive API Reference
  url: https://domani.run/docs