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-verify-service-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: 3.2.0
info:
title: domani.run Verify Service 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: Verify Service
paths:
/api/domains/{domain}/verify-service:
post:
operationId: verifyService
summary: Add DNS records to verify domain ownership for a third-party service
description: 'Adds the correct DNS records (TXT, CNAME) to prove domain ownership to a third-party service. Supports Stripe, Google Search Console, AWS SES, Postmark, Resend, Facebook, HubSpot, and Microsoft 365. Unknown service names fall back to a generic TXT record.
Records are merged with existing DNS - existing records are preserved.
Mail routing: a change to where the domain''s mail is delivered (its MX or NS records, the address records an MX host inside the zone resolves through, or those of a host that receives Domani mail and publishes no MX) needs the `email:auth_secrets` scope, since whoever receives the mail receives its sign-in codes. Without it the request answers 403 INSUFFICIENT_SCOPE before anything changes, and a token confined to mailboxes answers 403 MAILBOX_CONFINED even with it. Other records need only `domains:write`. Every routing change is recorded in the audit log.'
tags:
- Verify Service
x-rateLimit:
limit: 30
window: 1 minute
x-codeSamples:
- lang: bash
label: cURL - Stripe verification
source: "curl -X POST https://domani.run/api/domains/mysite.com/verify-service \\\n -H \"Authorization: Bearer domani_sk_xxx\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"service\": \"stripe\", \"token\": \"abc123def456\"}'"
- lang: bash
label: cURL - Google Search Console
source: "curl -X POST https://domani.run/api/domains/mysite.com/verify-service \\\n -H \"Authorization: Bearer domani_sk_xxx\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\"service\": \"google-search-console\", \"token\": \"abcdef123456\"}'"
parameters:
- name: domain
in: path
required: true
schema:
type: string
example: mysite.com
description: Domain name you own
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- service
- token
properties:
service:
type: string
description: Service name (e.g. stripe, google-search-console, aws-ses, postmark, resend, facebook, hubspot, microsoft-365)
example: stripe
token:
type: string
description: Verification token provided by the service
example: abc123def456
examples:
stripe:
summary: Stripe
value:
service: stripe
token: abc123def456
google:
summary: Google Search Console
value:
service: google-search-console
token: abcdef123456
aws:
summary: AWS SES
value:
service: aws-ses
token: EXAMPLE+abc123
generic:
summary: Generic (any service)
value:
service: my-saas
token: verify-my-domain-xyz
responses:
'200':
description: Verification records added
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:
domain:
type: string
service:
type: string
service_display_name:
type: string
known_service:
type: boolean
records_added:
type: array
items:
$ref: '#/components/schemas/DnsRecord'
total_records:
type: integer
docs:
type: string
format: uri
nullable: true
hint:
type: string
example:
domain: mysite.com
service: stripe
service_display_name: Stripe
known_service: true
records_added:
- type: TXT
name: '@'
value: stripe-verification=abc123def456
ttl: 3600
total_records: 3
docs: https://docs.stripe.com/identity/verification-checks/selfie#domain-verification
hint: Stripe verification records added. Return to Stripe to complete verification.
'400':
description: Invalid request parameters
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Missing 'service' parameter
code: MISSING_PARAMETER
hint: 'Send { service: ''stripe'', token: ''your-token'' }'
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
'403':
description: Moving the domain's mail needs the email:auth_secrets scope (INSUFFICIENT_SCOPE) and a token not confined to mailboxes (MAILBOX_CONFINED)
'404':
description: Domain not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Domain not found
code: NOT_FOUND
hint: Verify the domain exists and belongs to you
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
get:
operationId: listVerifyServices
summary: List supported services for domain verification
description: Returns all known services with their names, descriptions, and documentation URLs. Unknown services fall back to a generic TXT record.
tags:
- Verify Service
x-rateLimit:
limit: 60
window: 1 minute
parameters:
- name: domain
in: path
required: true
schema:
type: string
example: mysite.com
description: Domain name you own
responses:
'200':
description: Available services
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:
domain:
type: string
services:
type: array
items:
type: object
properties:
name:
type: string
displayName:
type: string
description:
type: string
docs:
type: string
format: uri
hint:
type: string
'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
'404':
description: Domain not found
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
example:
error: Domain not found
code: NOT_FOUND
hint: Verify the domain exists and belongs to you
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
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
DnsRecord:
type: object
properties:
type:
type: string
enum:
- A
- AAAA
- CNAME
- MX
- TXT
- NS
- SRV
- CAA
- TLSA
description: DNS record type. TLSA publishes a DANE record; its value is the rdata 'usage selector matching-type hex-data'.
name:
type: string
example: '@'
description: Record name (@ for root, or subdomain, e.g. _443._tcp for TLSA)
value:
type: string
example: 76.76.21.21
description: Record value (IP address, hostname, or TLSA rdata like '3 1 1 abc123...')
ttl:
type: integer
example: 3600
description: Time to live in seconds
priority:
type: integer
description: Priority value (required for MX records)
required:
type: boolean
description: False when the zone Domani manages for the domain cannot hold the record (a TXT longer than the registrar accepts); such a record is shown but not needed for mail to work. Absent on plain zone records.
required:
- type
- name
- value
- ttl
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