{"openapi":"3.1.0","info":{"title":"AgentDomains API","version":"1.0.0","description":"API-first domain registrar for autonomous AI agents. Ed25519 auth (SSH, hex, or base58/Solana), human-in-the-loop Stripe payments.","contact":{"email":"support@gentik.io"}},"servers":[{"url":"https://www.agentdomains.dev","description":"Production"}],"paths":{"/api/domains/check":{"get":{"summary":"Check domain availability and get pricing","operationId":"checkDomain","tags":["domains"],"responses":{"200":{"description":"Check domain availability and get pricing","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string"},"available":{"type":"boolean","description":"boolean"},"status":{"type":"string","description":"string (available | taken | invalid)"},"pricing":{"type":"object","properties":{"registration":{"type":"number","description":"number (cents USD)"},"renewal":{"type":"number","description":"number (cents USD)"},"currency":{"type":"string","description":"string"}}},"wholesale":{"type":"object","properties":{"registration":{"type":"number","description":"number (cents USD)"},"renewal":{"type":"number","description":"number (cents USD)"}}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"domain","in":"query","required":true,"description":"string (required) — domain to check, e.g. example.dev","schema":{"type":"string"}}],"description":"No auth required. Prices include tiered markup."}},"/api/domains/check/bulk":{"post":{"summary":"Bulk domain availability check (max 50 domains)","operationId":"bulkCheckDomains","tags":["domains"],"responses":{"201":{"description":"Bulk domain availability check (max 50 domains)","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","description":"array of { domain, available, status, pricing }"},"count":{"type":"number","description":"number"},"available":{"type":"number","description":"number"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"string","description":"string[] (1–50 domain names)"}}}}}}}},"/api/domains/pricing":{"get":{"summary":"Get pricing for all supported TLDs","operationId":"getAllPricing","tags":["domains"],"responses":{"200":{"description":"Get pricing for all supported TLDs","content":{"application/json":{"schema":{"type":"object","properties":{"pricing":{"type":"object","description":"Record<tld, { registration, renewal, currency }>"},"markup":{"type":"number","description":"number (cents)"},"note":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/api/domains/pricing/{domain}":{"get":{"summary":"Get pricing for a specific domain","operationId":"getDomainPricing","tags":["domains"],"responses":{"200":{"description":"Get pricing for a specific domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string"},"pricing":{"type":"object","properties":{"registration":{"type":"number","description":"number (cents USD)"},"renewal":{"type":"number","description":"number (cents USD)"},"currency":{"type":"string","description":"string"}}},"wholesale":{"type":"object","properties":{"registration":{"type":"number","description":"number (cents)"},"renewal":{"type":"number","description":"number (cents)"}}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/auth/challenge":{"post":{"summary":"Request a signing challenge for authentication (SSH Ed25519 or raw Ed25519)","operationId":"getChallenge","tags":["authentication"],"responses":{"201":{"description":"Request a signing challenge for authentication (SSH Ed25519 or raw Ed25519)","content":{"application/json":{"schema":{"type":"object","properties":{"challengeId":{"type":"string","description":"string"},"challenge":{"type":"string","description":"string — the string to sign"},"expiresAt":{"type":"string","description":"string (ISO 8601)"},"fingerprint":{"type":"string","description":"string (SHA256:...)"},"keyFormat":{"type":"string","description":"string (ssh | ed25519) — detected key format"},"returning":{"type":"boolean","description":"boolean — true if key was seen before"},"sign":{"type":"string","description":"string — signing instructions (ssh-keygen command for SSH keys, description for raw keys)"},"signExamples":{"type":"object","description":"object (raw Ed25519 only) — { node, python, solana } code snippets"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"publicKey":{"type":"string","description":"string — SSH Ed25519 key (ssh-ed25519 AAAA...), hex Ed25519 key (64 chars), or base58 Ed25519 key (Solana-style)"}}}}}}}},"/api/auth/verify":{"post":{"summary":"Verify a signed challenge and receive an API key","operationId":"verifyChallenge","tags":["authentication"],"responses":{"201":{"description":"Verify a signed challenge and receive an API key","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"string (authenticated | created)"},"agentId":{"type":"string","description":"string"},"fingerprint":{"type":"string","description":"string"},"apiKey":{"type":"string","description":"string — save this! Only shown once"},"apiKeyPrefix":{"type":"string","description":"string"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"challengeId":{"type":"string","description":"string — from /api/auth/challenge"},"signature":{"type":"string","description":"string — SSH SSHSIG signature, hex Ed25519 signature (128 chars), or base64 Ed25519 signature"}}}}}},"description":"Save your API key — it won't be shown again. Accepts both SSH SSHSIG and raw Ed25519 signatures."}},"/api/auth/login-link":{"post":{"summary":"Generate a temporary login link for the agent dashboard","operationId":"getLoginLink","tags":["authentication"],"responses":{"201":{"description":"Generate a temporary login link for the agent dashboard","content":{"application/json":{"schema":{"type":"object","properties":{"loginUrl":{"type":"string","description":"string — one-time login URL (expires in 5 minutes)"},"expiresAt":{"type":"string","description":"string (ISO 8601)"},"expiresIn":{"type":"number","description":"number — seconds until expiry"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}]}},"/api/auth/recover":{"post":{"summary":"Initiate account recovery via email","operationId":"initiateRecovery","tags":["authentication"],"responses":{"201":{"description":"Initiate account recovery via email","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string — always returns the same message to prevent enumeration"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"string — email used during domain registration"}}}}}}}},"/api/auth/recover/confirm":{"post":{"summary":"Confirm account recovery and receive a new API key","operationId":"confirmRecovery","tags":["authentication"],"responses":{"201":{"description":"Confirm account recovery and receive a new API key","content":{"application/json":{"schema":{"type":"object","properties":{"apiKey":{"type":"string","description":"string — new API key (save it, shown once)"},"apiKeyPrefix":{"type":"string","description":"string"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"string — recovery token from the email link"}}}}}}}},"/api/version":{"get":{"summary":"Get API version and deployment info","operationId":"getVersion","tags":["discovery"],"responses":{"200":{"description":"Get API version and deployment info","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"string","description":"string"},"environment":{"type":"string","description":"string"},"branch":{"type":"string","description":"string"},"features":{"type":"string","description":"string[]"},"deployedAt":{"type":"string","description":"string (ISO 8601)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/api/health":{"get":{"summary":"Health check endpoint (supports ?detailed=true with admin key)","operationId":"healthCheck","tags":["discovery"],"responses":{"200":{"description":"Health check endpoint (supports ?detailed=true with admin key)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"string (ok)"},"timestamp":{"type":"string","description":"string (ISO 8601)"},"database":{"type":"object","description":"object (detailed only) — { connected: boolean, latencyMs: number }"},"pendingInvoices":{"type":"number","description":"number (detailed only)"},"failedInvoices":{"type":"number","description":"number (detailed only)"},"activeAgents":{"type":"number","description":"number (detailed only)"},"activeDomains":{"type":"number","description":"number (detailed only)"},"rateLimitStoreSize":{"type":"number","description":"number (detailed only)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"detailed","in":"query","required":false,"description":"string (optional) — 'true' to get detailed stats (requires x-admin-key header)","schema":{"type":"string"}}],"description":"Basic mode requires no auth. Detailed mode requires x-admin-key header."}},"/api/account":{"get":{"summary":"Get account info, balance, and recent transactions","operationId":"getAccount","tags":["account"],"responses":{"200":{"description":"Get account info, balance, and recent transactions","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"string"},"fingerprint":{"type":"string","description":"string"},"apiKeyPrefix":{"type":"string","description":"string"},"domainCount":{"type":"number","description":"number"},"creditBalance":{"type":"number","description":"number — credit balance in cents"},"creditBalanceFormatted":{"type":"string","description":"string — e.g. '$12.50'"},"cardSaved":{"type":"boolean","description":"boolean — whether a card is saved for auto-renewal"},"autoRenewEnabled":{"type":"boolean","description":"boolean — whether auto-renewal charging is enabled"},"expiringDomains":{"type":"array","description":"array of { domain, expiresAt, daysRemaining } — domains expiring within 30 days"},"recentTransactions":{"type":"array","description":"array"},"createdAt":{"type":"string","description":"string (ISO 8601)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}]},"delete":{"summary":"Soft-delete your account (anonymize PII, deactivate API keys, retain domains)","operationId":"deleteAccount","tags":["account"],"responses":{"200":{"description":"Soft-delete your account (anonymize PII, deactivate API keys, retain domains)","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Confirmation message"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Domains and transactions are retained for ICANN compliance."}},"/api/domains":{"get":{"summary":"List your registered domains","operationId":"listDomains","tags":["domains"],"responses":{"200":{"description":"List your registered domains","content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","description":"array of { id, domain, status, expiresAt, dnsExternallyManaged, createdAt }"},"total":{"type":"number","description":"number"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}]}},"/api/domains/{domain}":{"get":{"summary":"Get details for a specific domain","operationId":"getDomain","tags":["domains"],"responses":{"200":{"description":"Get details for a specific domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","description":"object — { id, domain, status, expiresAt, autoRenew, dnsExternallyManaged, emailEnabled, createdAt, updatedAt, invoice? }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/domains/register":{"post":{"summary":"Register a new domain","operationId":"registerDomain","tags":["domains"],"responses":{"201":{"description":"Register a new domain","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"},"paymentUrl":{"type":"string","description":"string — payment page URL (invoice method) or undefined (credits)"},"invoice":{"type":"object","description":"{ id, amount, amountFormatted, status, expiresAt } (invoice method)"},"domain":{"type":"string","description":"string"},"channel":{"type":"object","description":"{ id, relay, endpoints: { poll, ws } } — relay channel for real-time updates (invoice method, when relay configured)"},"nextSteps":{"type":"object","description":"object — guidance for what to do next"},"cost":{"type":"object","description":"object — { amount, amountFormatted, previousBalance, newBalance } (credits method only)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCredits"}}}},"409":{"description":"Domain already registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainConflict"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string — domain to register (required)"},"autoRenew":{"type":"boolean","description":"boolean — enable auto-renewal (optional, default true). Syncs with registrar."},"period":{"type":"number","description":"number (optional, default 1) — years to register. Some TLDs have constraints: .ai min 2 yrs, .co max 5 yrs. Check GET /api/domains/tlds for minPeriod/maxPeriod per TLD."},"paymentMethod":{"type":"string","description":"string — 'credits' or 'invoice' (optional, default 'invoice'). 'credits' pays from credit balance; 'invoice' creates a Stripe payment page."},"registrant":{"type":"object","properties":{"firstName":{"type":"string","description":"string — first name"},"lastName":{"type":"string","description":"string — last name"},"organization":{"type":"string","description":"string — organization name (optional)"},"email":{"type":"string","description":"string — email address"},"phone":{"type":"string","description":"string — E.164 format, e.g. +1.5551234567"},"address":{"type":"object","properties":{"street":{"type":"string","description":"string — street address"},"city":{"type":"string","description":"string — city"},"state":{"type":"string","description":"string — state/province"},"postalCode":{"type":"string","description":"string — postal code"},"country":{"type":"string","description":"string — ISO 3166-1 alpha-2 country code"}}}},"description":"object (required) — ICANN registrant info"}},"required":["domain","registrant"]}}}},"description":"Registrant is required on every request. Payment options: paymentMethod 'invoice' (default) creates a Stripe payment page; paymentMethod 'credits' deducts from credit balance instantly. Invoice responses include a relay channel for real-time payment and registration updates via polling or WebSocket. ICANN requires accurate registrant info. A verification email is sent to registrant.email — domain will be suspended if not verified within 14 days."}},"/api/domains/register/batch":{"post":{"summary":"Register multiple domains in one request","operationId":"batchRegisterDomains","tags":["domains"],"responses":{"201":{"description":"Register multiple domains in one request","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"},"paymentUrl":{"type":"string","description":"string — payment page URL (invoice method) or undefined (credits)"},"invoice":{"type":"object","description":"{ id, amount, amountFormatted, status, expiresAt } (invoice method)"},"domains":{"type":"array","description":"array of { domain, cost }"},"channel":{"type":"object","description":"{ id, relay, endpoints: { poll, ws } } — relay channel for real-time updates (invoice method, when relay configured)"},"results":{"type":"array","description":"array of { domain, status, domainId?, error? } (credits method only)"},"nextSteps":{"type":"object","description":"object — guidance for what to do next"},"cost":{"type":"object","description":"object — { totalCharged, refunded, previousBalance, newBalance } (credits method only)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCredits"}}}},"409":{"description":"Domain already registered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainConflict"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","description":"array (1–20) of { domain: string, registrant?: object } (required)"},"period":{"type":"number","description":"number (optional, default 1) — years to register. Some TLDs have constraints: .ai min 2 yrs, .co max 5 yrs. Check GET /api/domains/tlds for minPeriod/maxPeriod per TLD."},"paymentMethod":{"type":"string","description":"string — 'credits' or 'invoice' (optional, default 'invoice'). 'credits' pays from credit balance; 'invoice' creates a Stripe payment page."},"registrant":{"type":"object","properties":{"firstName":{"type":"string","description":"string — first name"},"lastName":{"type":"string","description":"string — last name"},"organization":{"type":"string","description":"string — organization name (optional)"},"email":{"type":"string","description":"string — email address"},"phone":{"type":"string","description":"string — E.164 format, e.g. +1.5551234567"},"address":{"type":"object","properties":{"street":{"type":"string","description":"string — street address"},"city":{"type":"string","description":"string — city"},"state":{"type":"string","description":"string — state/province"},"postalCode":{"type":"string","description":"string — postal code"},"country":{"type":"string","description":"string — ISO 3166-1 alpha-2 country code"}}}},"description":"object (required) — ICANN registrant info (per-domain overrides allowed)"}},"required":["domains","registrant"]}}}},"description":"Tiered markup per domain based on wholesale cost. Payment options: paymentMethod 'invoice' (default) creates a Stripe payment page; paymentMethod 'credits' deducts from credit balance instantly. Invoice responses include a relay channel for real-time updates. Multi-year supported via period param. Some TLDs have period constraints (e.g. .ai min 2 yrs). ICANN requires accurate registrant info."}},"/api/domains/{domain}/renew":{"post":{"summary":"Renew a domain (creates invoice + payment link)","operationId":"renewDomain","tags":["management"],"responses":{"201":{"description":"Renew a domain (creates invoice + payment link)","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"},"paymentUrl":{"type":"string","description":"string — payment page URL"},"invoice":{"type":"object","description":"{ id, amount, amountFormatted, status, paymentUrl, expiresAt }"},"domain":{"type":"string","description":"string"},"domainExpiresAt":{"type":"string","description":"string (ISO 8601) — current domain expiry"},"period":{"type":"number","description":"number"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"},"nextSteps":{"type":"object","description":"object — guidance for what to do next"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"period":{"type":"number","description":"number (optional, default 1) — years to renew. Some TLDs have constraints: .ai min 2 yrs, .co max 5 yrs."}}}}}},"description":"Creates an invoice and returns a payment page URL to send to your human. Renewal is fulfilled automatically on payment."}},"/api/domains/{domain}/auto-renew":{"put":{"summary":"Toggle auto-renewal for a domain (syncs with registrar)","operationId":"setDomainAutoRenew","tags":["management"],"responses":{"200":{"description":"Toggle auto-renewal for a domain (syncs with registrar)","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string"},"autoRenew":{"type":"boolean","description":"boolean — new auto-renew state"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"boolean — true to enable, false to disable"}}}}}},"description":"Updates both our billing system and the registrar auto-renew flag in lockstep. If you have a saved card with auto-renew enabled, domains with autoRenew=true will be renewed automatically before expiry."}},"/api/domains/{domain}/nameservers":{"get":{"summary":"Get current nameservers for a domain","operationId":"getNameservers","tags":["management"],"responses":{"200":{"description":"Get current nameservers for a domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"nameservers":{"type":"string","description":"string[]"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}]},"put":{"summary":"Update nameservers for a domain","operationId":"updateNameservers","tags":["management"],"responses":{"200":{"description":"Update nameservers for a domain","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"domain":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"nameservers":{"type":"string","description":"string[]"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nameservers":{"type":"string","description":"string[] (1–13 nameserver hostnames)"}}}}}}}},"/api/domains/{domain}/email-forwarding":{"get":{"summary":"Get email forwarding rules","operationId":"getEmailForwarding","tags":["management"],"responses":{"200":{"description":"Get email forwarding rules","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"forwards":{"type":"array","description":"array of { alias, forwardTo }"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}]},"put":{"summary":"Set email forwarding rules","operationId":"setEmailForwarding","tags":["management"],"responses":{"200":{"description":"Set email forwarding rules","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"domain":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"forwards":{"type":"array","description":"array of { alias, forwardTo }"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"forwards":{"type":"array","description":"array of { alias, forwardTo } (1–50)"}}}}}}}},"/api/domains/{domain}/contacts":{"get":{"summary":"Get current WHOIS contacts for a domain","operationId":"getContacts","tags":["management"],"responses":{"200":{"description":"Get current WHOIS contacts for a domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"contacts":{"type":"object","properties":{"registrant":{"type":"string","description":"ContactInfo"},"admin":{"type":"string","description":"ContactInfo"},"tech":{"type":"string","description":"ContactInfo"},"auxBilling":{"type":"string","description":"ContactInfo"}}},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"description":"Returns all four contact types: Registrant, Admin, Tech, AuxBilling."},"put":{"summary":"Update WHOIS contacts for a domain","operationId":"updateContacts","tags":["management"],"responses":{"200":{"description":"Update WHOIS contacts for a domain","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"domain":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"contacts":{"type":"object","description":"{ registrant, admin, tech, auxBilling }"},"important":{"type":"string","description":"string — ICANN verification warning"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"registrant":{"type":"string","description":"ContactInfo (optional) — update registrant contact"},"admin":{"type":"string","description":"ContactInfo (optional) — update admin contact"},"tech":{"type":"string","description":"ContactInfo (optional) — update tech contact"},"auxBilling":{"type":"string","description":"ContactInfo (optional) — update billing contact"}}}}}},"description":"At least one contact type must be provided. If you change the registrant email, ICANN requires re-verification within 14 days or the domain will be suspended."}},"/api/domains/{domain}/dns":{"get":{"summary":"List DNS records for a domain","operationId":"listDnsRecords","tags":["dns"],"responses":{"200":{"description":"List DNS records for a domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"nameserversConfigured":{"type":"boolean","description":"boolean"},"records":{"type":"array","description":"array of { id, type, name, content, priority, weight, port }"},"recordCount":{"type":"number","description":"number"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}]},"post":{"summary":"Create a DNS record","operationId":"createDnsRecord","tags":["dns"],"responses":{"201":{"description":"Create a DNS record","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"message":{"type":"string","description":"string"},"expiresAt":{"type":"string","description":"string (ISO 8601) — domain expiry date"},"record":{"type":"object","description":"{ type, name, content, priority, weight, port }"},"expirationWarning":{"type":"object","description":"object (optional) — { message, daysRemaining, renewEndpoint }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","description":"string (A | AAAA | CNAME | TXT | MX | NS | SRV | CAA)"},"name":{"type":"string","description":"string (subdomain or @ for root, default @)"},"content":{"type":"string","description":"string (record value)"},"priority":{"type":"number","description":"number (optional, for MX/SRV)"},"weight":{"type":"number","description":"number (optional, for SRV)"},"port":{"type":"number","description":"number (optional, for SRV)"}}}}}},"description":"Automatically creates DNS zone if one doesn't exist."},"delete":{"summary":"Delete a DNS record","operationId":"deleteDnsRecord","tags":["dns"],"responses":{"200":{"description":"Delete a DNS record","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}},{"name":"type","in":"query","required":true,"description":"string (required) — record type","schema":{"type":"string"}},{"name":"name","in":"query","required":true,"description":"string (required) — subdomain or @","schema":{"type":"string"}},{"name":"content","in":"query","required":false,"description":"string (optional) — narrow match by content","schema":{"type":"string"}}],"description":"Query params: ?type=A&name=www&content=1.2.3.4"}},"/api/domains/{domain}/dns/enable":{"post":{"summary":"Re-enable Cloudflare DNS (restore nameservers after external change)","operationId":"enableCloudflareDns","tags":["dns"],"responses":{"201":{"description":"Re-enable Cloudflare DNS (restore nameservers after external change)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"domain":{"type":"string","description":"string"},"message":{"type":"string","description":"string"},"nameservers":{"type":"string","description":"string[] — restored Cloudflare nameservers"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"description":"Restores Cloudflare nameservers at the registrar and marks DNS as managed. If no Cloudflare zone exists, runs initial setup."}},"/api/invoices":{"get":{"summary":"List your invoices","operationId":"listInvoices","tags":["account"],"responses":{"200":{"description":"List your invoices","content":{"application/json":{"schema":{"type":"object","properties":{"invoices":{"type":"array","description":"array of { id, amount, amountFormatted, status, description, itemType, domain, expiresAt, fulfilledAt, createdAt }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"description":"string (optional) — filter by status","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"number (optional, default 50, max 100)","schema":{"type":"string"}}]}},"/api/invoices/{id}":{"get":{"summary":"Get invoice details","operationId":"getInvoice","tags":["account"],"responses":{"200":{"description":"Get invoice details","content":{"application/json":{"schema":{"type":"object","properties":{"invoice":{"type":"object","description":"{ id, amount, amountFormatted, status, description, itemType, itemData, payment, domain, expiresAt, fulfilledAt, createdAt }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/api/invoices/{id}/pay":{"post":{"summary":"Get a new Stripe payment link for a pending invoice","operationId":"payInvoice","tags":["account"],"responses":{"201":{"description":"Get a new Stripe payment link for a pending invoice","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"},"checkoutUrl":{"type":"string","description":"string — Stripe Checkout URL"},"sessionId":{"type":"string","description":"string — Stripe session ID"},"invoice":{"type":"object","description":"{ id, amount, amountFormatted, description, expiresAt }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"description":"Only works on PENDING invoices that haven't expired. Useful when original checkout link expired."}},"/api/domains/tlds":{"get":{"summary":"List all supported TLDs with pricing and agent-friendly flags","operationId":"listTlds","tags":["domains"],"responses":{"200":{"description":"List all supported TLDs with pricing and agent-friendly flags","content":{"application/json":{"schema":{"type":"object","properties":{"tlds":{"type":"array","description":"array of { tld, registration, renewal, unit, currency, agentFriendly, minPeriod, maxPeriod }"},"count":{"type":"number","description":"number"},"markupModel":{"type":"string","description":"string — 'tiered'"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"description":"No auth required. Prices in cents USD. agentFriendly indicates TLDs well-suited for AI agents. minPeriod/maxPeriod show registration period constraints per TLD (e.g. .ai requires min 2 yrs)."}},"/llms.txt":{"get":{"summary":"LLM-optimized plain text API description","operationId":"getLlmsTxt","tags":["discovery"],"responses":{"200":{"description":"LLM-optimized plain text API description","content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"string — plain text API description optimized for LLM consumption"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"description":"Returns text/plain. Designed for AI agents to understand the API quickly."}},"/api/email/plans":{"get":{"summary":"List email hosting plans and pricing","operationId":"getEmailPlans","tags":["email"],"responses":{"200":{"description":"List email hosting plans and pricing","content":{"application/json":{"schema":{"type":"object","properties":{"pricing":{"type":"object","properties":{"basePriceCents":{"type":"number","description":"number — base price per mailbox per month (500 = $5)"},"additionalStoragePriceCents":{"type":"number","description":"number — per 5GB block per month (200 = $2)"},"maxStorageGB":{"type":"number","description":"number"}}},"tiers":{"type":"array","description":"array of { storageGB, monthlyPriceCents, monthlyPrice }"},"features":{"type":"string","description":"string[]"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"description":"No auth required. Shows pricing tiers and features for hosted email."}},"/api/email/mailboxes":{"post":{"summary":"Create a new email mailbox on your domain","operationId":"createMailbox","tags":["email"],"responses":{"201":{"description":"Create a new email mailbox on your domain","content":{"application/json":{"schema":{"type":"object","properties":{"mailbox":{"type":"object","description":"{ id, address, fullAddress, domain, quotaGB, status, monthlyPrice }"},"checkoutUrl":{"type":"string","description":"string (present if payment needed) — Stripe Checkout URL"},"subscription":{"type":"object","description":"{ id, status } (present if paid with saved card)"},"credentials":{"type":"object","description":"{ email, password, tag } (present on synchronous creation — saved card or existing subscription)"},"connection":{"type":"object","description":"{ imap, smtp, webmail, username } (present with credentials)"},"warning":{"type":"string","description":"string (present with credentials) — reminder password is shown only once"},"monthlyPriceCents":{"type":"number","description":"number"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string","description":"string (required) — your registered domain name"},"address":{"type":"string","description":"string (required) — local part of the email (e.g. 'hello' for hello@example.com)"},"quotaGB":{"type":"number","description":"number (optional, default 5) — storage in GB, must be multiple of 5, max 100"}},"required":["domain","address"]}}}},"description":"Closed beta — requires email beta access (403 without it). Requires an active domain registered through AgentDomains. If you have a saved card, the subscription starts immediately (201) with IMAP/SMTP credentials included. Otherwise returns a checkout URL (202) — call POST /api/email/mailboxes/{id}/credentials after payment to get credentials. Adding to an existing domain subscription doesn't need new payment."},"get":{"summary":"List all your email mailboxes","operationId":"listMailboxes","tags":["email"],"responses":{"200":{"description":"List all your email mailboxes","content":{"application/json":{"schema":{"type":"object","properties":{"mailboxes":{"type":"array","description":"array of { id, address, fullAddress, domain, quotaGB, status, monthlyPrice }"},"total":{"type":"number","description":"number"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Closed beta — requires email beta access."}},"/api/email/mailboxes/{id}":{"get":{"summary":"Get mailbox details (real-time data from email provider)","operationId":"getMailbox","tags":["email"],"responses":{"200":{"description":"Get mailbox details (real-time data from email provider)","content":{"application/json":{"schema":{"type":"object","properties":{"mailbox":{"type":"object","description":"{ id, fullAddress, quotaGB, usedMB, suspended, status, monthlyPrice }"},"connection":{"type":"object","description":"{ imap: { host, port, security }, smtp: { host, port, security }, webmail, username }"},"credentialsEndpoint":{"type":"string","description":"string — POST this to generate IMAP/SMTP credentials"},"source":{"type":"string","description":"string — 'live' (real-time) or 'cache'"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"description":"Closed beta — requires email beta access. Queries the email provider for real-time quota usage and status. Includes connection info for IMAP/SMTP/webmail."},"patch":{"summary":"Resize mailbox storage (triggers billing proration)","operationId":"resizeMailbox","tags":["email"],"responses":{"200":{"description":"Resize mailbox storage (triggers billing proration)","content":{"application/json":{"schema":{"type":"object","properties":{"mailbox":{"type":"object","description":"{ id, fullAddress, quotaGB, previousQuotaGB, monthlyPrice }"},"proration":{"type":"string","description":"string — 'upgrade' or 'downgrade'"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"quotaGB":{"type":"number","description":"number (required) — new storage in GB, must be multiple of 5"}},"required":["quotaGB"]}}}},"description":"Closed beta — requires email beta access. Updates email provider first, then billing. Stripe auto-prorates the change."},"delete":{"summary":"Delete a mailbox (immediately deprovisions)","operationId":"deleteMailbox","tags":["email"],"responses":{"200":{"description":"Delete a mailbox (immediately deprovisions)","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"},"mailboxId":{"type":"string","description":"string"},"subscriptionCancelled":{"type":"boolean","description":"boolean — true if this was the last mailbox on the domain"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"description":"Closed beta — requires email beta access. Immediately removes the mailbox from the email provider. If it was the last mailbox on the domain, the subscription is cancelled entirely."}},"/api/email/mailboxes/{id}/credentials":{"post":{"summary":"Generate IMAP/SMTP credentials (app password) for a mailbox","operationId":"generateMailboxCredentials","tags":["email"],"responses":{"201":{"description":"Generate IMAP/SMTP credentials (app password) for a mailbox","content":{"application/json":{"schema":{"type":"object","properties":{"credentials":{"type":"object","properties":{"email":{"type":"string","description":"string — full email address"},"password":{"type":"string","description":"string — app password (XXXX-XXXX-XXXX-XXXX format, shown once)"},"tag":{"type":"string","description":"string — the tag for this credential"}}},"connection":{"type":"object","properties":{"imap":{"type":"object","description":"{ host, port: 993, security: 'SSL/TLS' }"},"smtp":{"type":"object","description":"{ host, port: 587, security: 'STARTTLS' }"},"webmail":{"type":"string","description":"string — webmail URL"},"username":{"type":"string","description":"string — login username (same as email)"}}},"warning":{"type":"string","description":"string — reminder that password is shown only once"},"maxAppPasswords":{"type":"number","description":"number — maximum app passwords per mailbox (4)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tag":{"type":"string","description":"string (optional, default 'agent-imap') — label for this credential (e.g. 'agent-imap', 'webmail')"}}}}}},"description":"Closed beta — requires email beta access. Each call generates a fresh app password. Up to 4 per mailbox. Rate limited to 5/hour. NOT idempotent — each call creates a new password."},"delete":{"summary":"Revoke an app password by tag","operationId":"revokeMailboxCredentials","tags":["email"],"responses":{"200":{"description":"Revoke an app password by tag","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"},"tag":{"type":"string","description":"string — the tag that was revoked"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"tag":{"type":"string","description":"string (required) — tag of the app password to revoke"}},"required":["tag"]}}}},"description":"Closed beta — requires email beta access. Permanently revokes the app password with the given tag. The password can no longer be used for IMAP/SMTP access."}},"/api/reports":{"post":{"summary":"Submit a problem report (auth optional — anonymous reports allowed)","operationId":"submitReport","tags":["support"],"responses":{"201":{"description":"Submit a problem report (auth optional — anonymous reports allowed)","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"string — report ID"},"category":{"type":"string","description":"string"},"subject":{"type":"string","description":"string"},"status":{"type":"string","description":"string — OPEN"},"createdAt":{"type":"string","description":"string (ISO 8601)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","description":"string (required) — DOMAIN | BILLING | EMAIL | DNS | ACCOUNT | OTHER"},"subject":{"type":"string","description":"string (required, 1–200 chars) — brief summary of the problem"},"description":{"type":"string","description":"string (required, 1–5000 chars) — detailed description"},"domainName":{"type":"string","description":"string (optional) — related domain name"},"contactEmail":{"type":"string","description":"string (optional, email) — for anonymous reporters to receive a reply"}},"required":["category"]}}}},"description":"Auth is optional. Authenticated agents get the report linked to their account. Anonymous reporters should provide a contactEmail to receive follow-up. Rate limited: 10/min authenticated, 5/min anonymous (per IP)."}},"/api/webhooks/stripe":{"post":{"summary":"Stripe webhook handler (internal — called by Stripe)","operationId":"stripeWebhook","tags":[],"responses":{"201":{"description":"Stripe webhook handler (internal — called by Stripe)","content":{"application/json":{"schema":{"type":"object","properties":{"received":{"type":"boolean","description":"boolean"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"description":"Requires valid Stripe webhook signature. Not for public use."}},"/api/admin/agents":{"get":{"summary":"List all agents with stats (admin only)","operationId":"listAgents","tags":["admin"],"responses":{"200":{"description":"List all agents with stats (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"agents":{"type":"array","description":"array of { id, fingerprint, createdAt, domainCount, invoiceCount, lastUsedAt }"},"nextCursor":{"type":"string","description":"string | null — pass as cursor for next page"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"search","in":"query","required":false,"description":"string (optional) — filter by fingerprint prefix","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"number (optional, default 50, max 100)","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"string (optional) — agent ID for cursor-based pagination","schema":{"type":"string"}}],"description":"Requires x-admin-key header matching ADMIN_KEY env var."}},"/api/admin/domains":{"get":{"summary":"List all domains with filters (admin only)","operationId":"adminListDomains","tags":["admin"],"responses":{"200":{"description":"List all domains with filters (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","description":"array of domain objects"},"nextCursor":{"type":"string","description":"string | null"},"total":{"type":"number","description":"number"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"status","in":"query","required":false,"description":"string (optional) — filter by domain status","schema":{"type":"string"}},{"name":"expiringWithin","in":"query","required":false,"description":"string (optional) — e.g. '30d' for domains expiring within 30 days","schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"description":"string (optional) — filter by agent","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"number (optional, default 50, max 100)","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"string (optional) — domain ID for cursor-based pagination","schema":{"type":"string"}}],"description":"Requires x-admin-key header."}},"/api/admin/invoices":{"get":{"summary":"List all invoices with filters (admin only)","operationId":"adminListInvoices","tags":["admin"],"responses":{"200":{"description":"List all invoices with filters (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"invoices":{"type":"array","description":"array of invoice objects"},"nextCursor":{"type":"string","description":"string | null"},"total":{"type":"number","description":"number"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"status","in":"query","required":false,"description":"string (optional) — filter by invoice status","schema":{"type":"string"}},{"name":"agentId","in":"query","required":false,"description":"string (optional) — filter by agent","schema":{"type":"string"}},{"name":"from","in":"query","required":false,"description":"string (optional) — ISO date range start","schema":{"type":"string"}},{"name":"to","in":"query","required":false,"description":"string (optional) — ISO date range end","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"number (optional, default 50, max 100)","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"string (optional) — invoice ID for cursor-based pagination","schema":{"type":"string"}}],"description":"Requires x-admin-key header."}},"/api/admin/invoices/{id}/retry":{"post":{"summary":"Retry fulfillment for a failed invoice (admin only)","operationId":"adminRetryInvoice","tags":["admin"],"responses":{"201":{"description":"Retry fulfillment for a failed invoice (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"message":{"type":"string","description":"string"},"invoiceId":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"description":"Requires x-admin-key header. Only works on FAILED invoices."}},"/api/admin/invoices/{id}/refund":{"post":{"summary":"Refund a paid invoice via Stripe (admin only)","operationId":"adminRefundInvoice","tags":["admin"],"responses":{"201":{"description":"Refund a paid invoice via Stripe (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"boolean"},"message":{"type":"string","description":"string"},"invoiceId":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"reason":{"type":"string","description":"string (optional) — reason for refund"}}}}}},"description":"Requires x-admin-key header. Invoice must have a Stripe payment intent."}},"/api/admin/verify-support-token":{"post":{"summary":"Verify a support token and get agent info (admin only)","operationId":"adminVerifySupportToken","tags":["admin"],"responses":{"201":{"description":"Verify a support token and get agent info (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean","description":"boolean"},"agent":{"type":"object","properties":{"id":{"type":"string","description":"string"},"fingerprint":{"type":"string","description":"string"},"createdAt":{"type":"string","description":"string (ISO 8601)"},"domainCount":{"type":"number","description":"number"}}},"tokenExpiresAt":{"type":"string","description":"string (ISO 8601)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"string — the support token from the agent's human"}}}}}},"description":"Requires x-admin-key header. Verifies HMAC signature and expiry."}},"/api/admin/reviews":{"get":{"summary":"List all reviews with optional status filter (admin only)","operationId":"adminListReviews","tags":["admin"],"responses":{"200":{"description":"List all reviews with optional status filter (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"reviews":{"type":"array","description":"array of review objects"},"nextCursor":{"type":"string","description":"string | null"},"total":{"type":"number","description":"number"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"status","in":"query","required":false,"description":"string (optional) — PENDING, APPROVED, REJECTED","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"number (optional, default 50, max 100)","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"string (optional) — review ID for pagination","schema":{"type":"string"}}],"description":"Requires x-admin-key header or admin session."}},"/api/admin/reviews/{reviewId}":{"put":{"summary":"Moderate a review — approve or reject (admin only)","operationId":"adminModerateReview","tags":["admin"],"responses":{"200":{"description":"Moderate a review — approve or reject (admin only)","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"string"},"status":{"type":"string","description":"string"},"moderatedBy":{"type":"string","description":"string"},"moderatedAt":{"type":"string","description":"string (ISO 8601)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"reviewId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"string (required) — APPROVED or REJECTED"},"note":{"type":"string","description":"string (optional) — internal moderation note"}},"required":["status"]}}}},"description":"Requires ADMIN role. SUPPORT users cannot moderate."}},"/api/admin/cleanup":{"post":{"summary":"Clean up expired challenges, idempotency keys, and invoices (admin/cron only)","operationId":"adminCleanup","tags":["admin"],"responses":{"201":{"description":"Clean up expired challenges, idempotency keys, and invoices (admin/cron only)","content":{"application/json":{"schema":{"type":"object","properties":{"cleaned":{"type":"object","description":"{ challenges, idempotencyKeys, invoices, domains, expiredDomains } — counts of cleaned records"},"timestamp":{"type":"string","description":"ISO 8601 timestamp"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Requires x-admin-key header or Vercel CRON_SECRET. Runs hourly via Vercel cron."}},"/api/admin/auto-renew":{"post":{"summary":"Process automatic domain renewals for expiring domains (admin/cron only)","operationId":"adminAutoRenew","tags":["admin"],"responses":{"201":{"description":"Process automatic domain renewals for expiring domains (admin/cron only)","content":{"application/json":{"schema":{"type":"object","properties":{"processed":{"type":"number","description":"number — total domains processed"},"chargedSuccessfully":{"type":"number","description":"number — domains auto-renewed via saved card"},"invoiceCreated":{"type":"number","description":"number — domains with manual invoices created"},"skipped":{"type":"number","description":"number — domains skipped (already renewed or pending)"},"failed":{"type":"number","description":"number — domains that failed to process"},"domainsChecked":{"type":"number","description":"number — total domains matching auto-renew criteria"},"timestamp":{"type":"string","description":"ISO 8601 timestamp"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Requires x-admin-key header or Vercel CRON_SECRET. Runs daily at 06:00 UTC via Vercel cron. Finds domains expiring within 30 days with autoRenew=true, attempts off-session card charge, falls back to creating a manual invoice."}},"/api/account/support-token":{"get":{"summary":"Generate a short-lived support token for human-agent verification","operationId":"getSupportToken","tags":["account"],"responses":{"200":{"description":"Generate a short-lived support token for human-agent verification","content":{"application/json":{"schema":{"type":"object","properties":{"supportToken":{"type":"string","description":"string — token to give to your human"},"expiresAt":{"type":"string","description":"string (ISO 8601) — token expiry (24 hours)"},"instructions":{"type":"string","description":"string — what to tell your human"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Rate limited to 5 requests per minute. Give the token to your human so they can include it when contacting support. Support verifies the token to confirm the human is authorized to act on your behalf."}},"/api/account/setup-card":{"post":{"summary":"Get a Stripe URL to save a card for auto-renewal","operationId":"setupCard","tags":["account"],"responses":{"201":{"description":"Get a Stripe URL to save a card for auto-renewal","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","description":"string — Stripe Checkout URL for card setup"},"sessionId":{"type":"string","description":"string — Stripe session ID"},"note":{"type":"string","description":"string (optional) — present if a card is already saved"},"nextSteps":{"type":"object","description":"object — guidance for what to do next"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Creates a Stripe Checkout Session in setup mode. Send the URL to your human to save a card. Once saved, auto-renewal is enabled automatically. If a card is already saved, the new card replaces the old one."}},"/api/account/card":{"get":{"summary":"Get saved card details","operationId":"getCard","tags":["account"],"responses":{"200":{"description":"Get saved card details","content":{"application/json":{"schema":{"type":"object","properties":{"saved":{"type":"boolean","description":"boolean — whether a card is saved"},"card":{"type":"object","description":"{ brand, last4, expMonth, expYear } (present if saved=true)"},"autoRenewEnabled":{"type":"boolean","description":"boolean — whether auto-renewal is enabled"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}]},"delete":{"summary":"Remove saved card and disable auto-renewal","operationId":"deleteCard","tags":["account"],"responses":{"200":{"description":"Remove saved card and disable auto-renewal","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Detaches the payment method from Stripe and disables auto-renewal. Domains will need manual renewal."}},"/api/account/auto-renew":{"get":{"summary":"Get auto-renewal status and card info","operationId":"getAutoRenew","tags":["account"],"responses":{"200":{"description":"Get auto-renewal status and card info","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"boolean — whether auto-renewal is enabled"},"cardSaved":{"type":"boolean","description":"boolean — whether a card is saved"},"card":{"type":"object","description":"{ brand, last4, expMonth, expYear } (present if card saved)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}]},"put":{"summary":"Enable or disable auto-renewal (requires saved card to enable)","operationId":"setAutoRenew","tags":["account"],"responses":{"200":{"description":"Enable or disable auto-renewal (requires saved card to enable)","content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"boolean — new auto-renewal state"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"boolean — true to enable, false to disable"}}}}}},"description":"Requires a saved card to enable. Call POST /api/account/setup-card first if no card is saved. When enabled, domains with autoRenew=true will be charged automatically before expiry."}},"/api/beta/apply":{"post":{"summary":"Apply for closed beta access (email or relay)","operationId":"applyForBeta","tags":["beta"],"responses":{"201":{"description":"Apply for closed beta access (email or relay)","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"\"pending\" | \"approved\" -- current application status"},"message":{"type":"string","description":"string"},"applicationId":{"type":"string","description":"string (present if newly created)"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"feature":{"type":"string","description":"\"email\" | \"relay\" (required)"},"email":{"type":"string","description":"string (optional) -- contact email for notifications"}},"required":["feature"]}}}},"description":"Returns existing status if already applied. Re-applies if previously rejected."}},"/api/beta/interest":{"post":{"summary":"Submit beta interest (no auth required, email-based)","operationId":"betaInterest","tags":["beta"],"responses":{"201":{"description":"Submit beta interest (no auth required, email-based)","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","description":"string (required) -- your email address"},"feature":{"type":"string","description":"\"email\" | \"relay\" (required)"}},"required":["email","feature"]}}}},"description":"Rate limited to 3/min per IP. Deduplicates by email+feature."}},"/api/beta/status":{"get":{"summary":"Check your beta access and pending applications","operationId":"getBetaStatus","tags":["beta"],"responses":{"200":{"description":"Check your beta access and pending applications","content":{"application/json":{"schema":{"type":"object","properties":{"betaFeatures":{"type":"string","description":"string[] -- granted beta feature slugs"},"features":{"type":"object","description":"object -- per-feature access status and application info"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}]}},"/api/reviews":{"post":{"summary":"Submit or update your review of the service","operationId":"submitReview","tags":["reviews"],"responses":{"201":{"description":"Submit or update your review of the service","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"string — review ID"},"status":{"type":"string","description":"string — PENDING (awaiting admin approval)"},"signed":{"type":"boolean","description":"boolean — whether signature verified"},"humanReviewUrl":{"type":"string","description":"string — URL to forward to your human for their review"},"verificationUrl":{"type":"string","description":"string | null — signature verification page URL"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rating":{"type":"number","description":"number (1-5, required)"},"body":{"type":"string","description":"string (10-2000 chars, required)"},"domainId":{"type":"string","description":"string (optional) — reference a specific domain"},"showOnHomepage":{"type":"boolean","description":"boolean (optional, default false) — allow display on homepage"},"showDomainName":{"type":"boolean","description":"boolean (optional, default false) — show domain name on homepage"},"signature":{"type":"string","description":"string (optional) — SSHSIG armored signature"},"signedAt":{"type":"string","description":"string (optional, ISO 8601) — required if signature provided"}}}}}},"description":"One review per agent (upserts). Sign with: ssh-keygen -Y sign -n gentik-review. Signed payload format: gentik-review:v1:{rating}:{sha256(body)}:{unix_timestamp}"},"get":{"summary":"List approved reviews (public, no auth)","operationId":"listReviews","tags":["reviews"],"responses":{"200":{"description":"List approved reviews (public, no auth)","content":{"application/json":{"schema":{"type":"object","properties":{"reviews":{"type":"array","description":"array of { id, rating, body, domainName, agentFingerprint, signed, verificationUrl, humanReview, createdAt }"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}}}},"/api/reviews/mine":{"get":{"summary":"Get your own review","operationId":"getMyReview","tags":["reviews"],"responses":{"200":{"description":"Get your own review","content":{"application/json":{"schema":{"type":"object","properties":{"review":{"type":"object","description":"{ id, rating, body, status, signed, humanReviewUrl, verificationUrl, humanReview, ... } | null"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}]}},"/api/reviews/verify/{reviewId}":{"get":{"summary":"Get cryptographic verification data for a signed review (public)","operationId":"verifyReview","tags":["reviews"],"responses":{"200":{"description":"Get cryptographic verification data for a signed review (public)","content":{"application/json":{"schema":{"type":"object","properties":{"review":{"type":"object","properties":{"id":{"type":"string","description":"string"},"rating":{"type":"number","description":"number"},"body":{"type":"string","description":"string"},"agentFingerprint":{"type":"string","description":"string"},"publicKey":{"type":"string","description":"string — agent's SSH public key"},"signature":{"type":"string","description":"string — SSHSIG armored signature"},"signedPayload":{"type":"string","description":"string — the exact string that was signed"},"verified":{"type":"boolean","description":"boolean — server-side verification result"}}}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"reviewId","in":"path","required":true,"schema":{"type":"string"}}],"description":"Also viewable at verify.gentik.io/{reviewId}"}},"/api/reviews/human/{token}":{"post":{"summary":"Submit a human review (token-based, no API auth)","operationId":"submitHumanReview","tags":["reviews"],"responses":{"201":{"description":"Submit a human review (token-based, no API auth)","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","description":"string — human review ID"},"message":{"type":"string","description":"string"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"string (optional) — display name"},"body":{"type":"string","description":"string (10-2000 chars, required)"},"rating":{"type":"number","description":"number (1-5, required)"}}}}}},"description":"Token is provided in the agent's review submission response (humanReviewUrl)."}},"/api/account/portal-link":{"post":{"summary":"Generate a temporary portal login link for your human","operationId":"getPortalLink","tags":["account"],"responses":{"201":{"description":"Generate a temporary portal login link for your human","content":{"application/json":{"schema":{"type":"object","properties":{"portalUrl":{"type":"string","description":"string — one-time login URL for the customer portal"},"expiresAt":{"type":"string","description":"string (ISO 8601) — link expiry"},"expiresIn":{"type":"number","description":"number — seconds until expiry"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"description":"Returns a URL your human can open to access a read/write portal for managing domains, DNS, and viewing invoices — no API key needed."}},"/api/audit-log":{"get":{"summary":"Get audit log entries for your account","operationId":"getAuditLog","tags":["account"],"responses":{"200":{"description":"Get audit log entries for your account","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","description":"array of { id, action, resource, domainName, actorType, metadata, createdAt }"},"nextCursor":{"type":"string","description":"string | null"}}}}}},"400":{"description":"Validation error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidationError"}}}},"401":{"description":"Invalid or missing API key"},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RateLimitError"}}}}},"security":[{"bearerAuth":[]}],"parameters":[{"name":"domain","in":"query","required":false,"description":"string (optional) — filter by domain name","schema":{"type":"string"}},{"name":"action","in":"query","required":false,"description":"string (optional) — filter by action (e.g. dns.create)","schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"number (optional, default 50, max 100)","schema":{"type":"string"}},{"name":"cursor","in":"query","required":false,"description":"string (optional) — audit log entry ID for pagination","schema":{"type":"string"}}],"description":"Returns audit log entries scoped to your agent account. Useful for tracking changes made by you, your human (via portal), or the system."}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key obtained from POST /api/auth/verify. Pass as: Authorization: Bearer <apiKey>"}},"schemas":{"ValidationError":{"type":"object","properties":{"error":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string","example":"invalid_type"},"path":{"type":"array","items":{"type":"string"}},"message":{"type":"string"}}}}}},"InsufficientCredits":{"type":"object","properties":{"error":{"type":"string","example":"Insufficient credit balance"},"balance":{"type":"number","description":"Current balance in cents"},"required":{"type":"number","description":"Required amount in cents"}}},"DomainConflict":{"type":"object","properties":{"error":{"type":"string","example":"Domain already registered in our system"}}},"RateLimitError":{"type":"object","properties":{"error":{"type":"string","example":"Rate limit exceeded"}}}}},"tags":[{"name":"domains","description":"Domain search, registration, and management"},{"name":"authentication","description":"Ed25519 challenge-response authentication (SSH or raw key formats)"},{"name":"discovery","description":"API metadata and health checks"},{"name":"account","description":"Account info, credits, and invoices"},{"name":"management","description":"Domain settings — renewal, nameservers, contacts, and email forwarding"},{"name":"dns","description":"DNS record management"},{"name":"email","description":"Email hosting (closed beta) — mailbox provisioning and management. Requires beta access. Apply via POST /api/beta/apply with { feature: \"email\" }."},{"name":"support","description":"Problem reporting and support"},{"name":"admin","description":"Admin endpoints (requires x-admin-key header)"},{"name":"beta","description":"Closed beta access — apply for email and relay features"},{"name":"reviews","description":"Review submission, verification, and human review"}]}