# AgentDomains API > Domain registrar built for autonomous AI agents. API-first. No dashboard required. > Payment via Stripe invoice pages — human-in-the-loop card payments. ## Authentication Ed25519 challenge-response. Submit a public key, sign a challenge, get an API key. Accepted key formats: SSH Ed25519 (ssh-ed25519 AAAA...), raw hex (64 chars), or base58 (Solana wallets). ## Quick Start ### Option A: SSH key (ssh-keygen) 1. POST /api/auth/challenge with { "publicKey": "ssh-ed25519 AAAA..." } 2. Sign the challenge: echo -n "" | ssh-keygen -Y sign -f ~/.ssh/key -n gentik - 3. POST /api/auth/verify with { "challengeId": "", "signature": "" } 4. Use the returned apiKey as: Authorization: Bearer ### Option B: Raw Ed25519 key (programmatic / crypto wallets) 1. POST /api/auth/challenge with { "publicKey": "<64-char hex or base58 public key>" } 2. Sign the challenge bytes directly with Ed25519: signature = ed25519_sign(private_key, challenge_bytes) 3. POST /api/auth/verify with { "challengeId": "", "signature": "" } 4. Use the returned apiKey as: Authorization: Bearer Works with: Node.js crypto.sign(), Python Ed25519PrivateKey.sign(), Solana/NEAR keypairs, any Ed25519 implementation. ## Registrant Info (Required) All registrations must include registrant info in the request body. ⚠️ CRITICAL — ICANN Verification & Registrant Accuracy: - ALL registrant information MUST be real and accurate. This is a LEGAL REQUIREMENT. - After registration, a verification email is sent to the registrant email address. - If the email is not verified within 14 DAYS, the domain WILL BE SUSPENDED. - No refunds can be offered for suspended domains. - DO NOT use fake names, placeholder emails, or invented addresses. - The email MUST belong to your human handler — they need to click the verification link. - Ask your human for their real info before registering. Don't guess or make it up. ## Payment Human-in-the-loop: every purchase returns a Stripe invoice payment page. Send the URL to your human — they pay with a card, and the domain registers automatically. No pre-funding needed. Alternatively, save a card for auto-renewal and domains will renew automatically (see Auto-Renewal section). Invoice responses include a `channel` object for real-time updates via Gentik Relay when available. If present, connect to the channel to receive events like `billing.payment_succeeded`, `domain.registered`, or `domain.registration_failed` instead of polling the invoice endpoint. If the `channel` field is absent, poll GET /api/invoices/{id} for status updates. ### Register a Domain POST /api/domains/register { "domain": "example.com", "registrant": { "firstName": "Jane", "lastName": "Smith", "email": "jane@example.com", "phone": "+1.4155551234", "address": { "street": "123 Main St", "city": "San Francisco", "state": "CA", "postalCode": "94102", "country": "US" } } } Returns: { "paymentUrl": "https://agentdomains.dev/pay/clxyz123", "invoice": { "id": "clxyz123", "amount": 1318, ... }, "channel": { // present when Relay is enabled "id": "invoice:clxyz123", "relay": "https://relay.gentik.io", "endpoints": { "poll": "/channels/invoice:clxyz123/events", "ws": "/channels/invoice:clxyz123/ws" } } } Send the paymentUrl to your human. They open it, see what you want to register and the price, enter their card, and pay. The domain registers automatically after payment. If the response includes a `channel` object, connect to the relay channel (WebSocket or poll) for real-time progress updates. The channel is provisioned at paid tier, so WebSocket works for all agents. If no `channel` is returned, poll GET /api/invoices/{id} instead. For multiple domains at once: POST /api/domains/register/batch { "registrant": { "firstName": "Jane", "lastName": "Smith", "email": "jane@example.com", "phone": "+1.4155551234", "address": { "street": "123 Main St", "city": "San Francisco", "state": "CA", "postalCode": "94102", "country": "US" } }, "domains": [{ "domain": "one.dev" }, { "domain": "two.dev" }] } Returns a single paymentUrl for all domains combined. ### Renew a Domain POST /api/domains/{domain}/renew { "period": 1 } Returns a paymentUrl. Send it to your human to pay for the renewal. ### Period Constraints Some TLDs have minimum/maximum registration periods enforced by their registry: - .ai — minimum 2 years (registration and renewal) - .co — maximum 5 years - All other TLDs — 1 to 10 years Check GET /api/domains/tlds for minPeriod/maxPeriod per TLD. If you request an invalid period, the API returns a 400 error with the constraints. ## What Your Human Sees When a human opens the payment URL, they see: - What you (the agent) want: "Your agent wants to register coolbot.dev" - The exact price: "$13.18 for 1 year" - Renewal price hint (for registrations) - Alternative TLD options (if provided) - Stripe card payment form ## Contact Management GET /api/domains/{domain}/contacts — returns all four WHOIS contact types. PUT /api/domains/{domain}/contacts — update one or more contact types. { "registrant": { "firstName": "Jane", "lastName": "Smith", "email": "jane@example.com", "phone": "+1.4155551234", "address": { "street": "123 Main St", "city": "SF", "state": "CA", "postalCode": "94102", "country": "US" } } } You only need to provide the contact types you want to change. The others are kept as-is. ⚠️ ICANN Email Verification: If you change the registrant email address, a new verification email is sent to the NEW address. That email MUST be verified within 14 days or the domain WILL BE SUSPENDED. Make sure the new email is real and accessible by your human handler. ## DNS Record Example POST /api/domains/{domain}/dns { "type": "A", "name": "@", "content": "1.2.3.4" } Supported types: A, AAAA, CNAME, MX, TXT, NS, SRV, CAA ## Email Forwarding GET /api/domains/{domain}/email-forwarding — returns current forwarding rules. PUT /api/domains/{domain}/email-forwarding — replace all forwarding rules. { "forwards": [ { "alias": "hello", "forwardTo": "jane@gmail.com" }, { "alias": "support", "forwardTo": "team@company.com" } ] } The "alias" field is the mailbox prefix (without @domain). The "forwardTo" field is the destination email. ## Email Hosting (Closed Beta) > Email hosting is in closed beta. You must have email beta access to use these endpoints. > To apply: POST /api/beta/apply with { "feature": "email" } > Check status: GET /api/beta/status?feature=email Provisioned hosted email on agent-owned domains. ### Pricing $5/mo base (1 mailbox, 5GB storage). Additional storage in 5GB blocks at $2/mo each. | Storage | Price/mo | |---------|----------| | 5 GB | $5 | | 10 GB | $7 | | 25 GB | $13 | | 50 GB | $23 | | 100 GB | $43 | ### Provisioning POST /api/email/mailboxes { "domain": "example.com", "address": "hello", "quotaGB": 5 } - If the agent has a saved card: auto-charged, mailbox created immediately with IMAP/SMTP credentials in the response. - If no saved card: returns a checkout URL. Send it to your human to pay. After payment, call POST /api/email/mailboxes/{id}/credentials to get login credentials. - First mailbox on a domain automatically configures MX records for email delivery. ### Accessing Email (IMAP/SMTP Credentials) POST /api/email/mailboxes/{id}/credentials { "tag": "agent-imap" } Returns: { "credentials": { "email": "hello@example.com", "password": "XXXX-XXXX-XXXX-XXXX", "tag": "agent-imap" }, "connection": { "imap": { "host": "mail.a.hostedemail.com", "port": 993, "security": "SSL/TLS" }, "smtp": { "host": "mail.a.hostedemail.com", "port": 587, "security": "STARTTLS" }, "webmail": "https://mail.agentdomains.dev", "username": "hello@example.com" } } - Each call generates a fresh app password (not idempotent). Up to 4 per mailbox. - Password is shown only once — store it securely. - Use different tags for different purposes: "agent-imap" for programmatic access, "webmail" for human webmail login. - Rate limited to 5 per hour. To revoke a credential: DELETE /api/email/mailboxes/{id}/credentials { "tag": "agent-imap" } ### Webmail (Human Access) 1. Generate credentials: POST /api/email/mailboxes/{id}/credentials with { "tag": "webmail" } 2. Tell your human: "Go to https://mail.agentdomains.dev, log in with hello@example.com / XXXX-XXXX-XXXX-XXXX" ### Resize Storage PATCH /api/email/mailboxes/{id} { "quotaGB": 25 } Stripe prorates the change automatically — you only pay the difference for the remainder of the billing period. ### Cancel DELETE /api/email/mailboxes/{id} Mailbox is cancelled at the end of the current billing period. No further charges. ## Domain Expiration & Auto-Renewal Domains expire unless renewed. You can enable auto-renewal so your domains are automatically charged and renewed before expiry. ### Setting Up Auto-Renewal 1. POST /api/account/setup-card — returns a Stripe URL. Send it to your human to save a card. 2. Once the card is saved, auto-renewal is enabled automatically for the account. 3. Domains default to autoRenew=true. Toggle per-domain with PUT /api/domains/{domain}/auto-renew. ### How Auto-Renewal Works - A daily cron checks for domains expiring within 30 days with autoRenew=true. - If the agent has a saved card, the card is charged off-session (no human needed). - If the card fails (declined, 3DS required, expired), a manual payment invoice is created. - The auto-renew setting syncs with the registrar — they're always in lockstep. ### Managing Cards & Auto-Renewal - GET /api/account/card — view saved card details (brand, last4, expiry) - DELETE /api/account/card — remove saved card and disable auto-renewal - GET /api/account/auto-renew — check auto-renewal status - PUT /api/account/auto-renew — enable/disable auto-renewal (requires saved card to enable) - PUT /api/domains/{domain}/auto-renew — toggle auto-renewal for a specific domain ### Manual Renewal You can always renew manually regardless of auto-renewal settings: POST /api/domains/{domain}/renew — returns a payment URL. ### Expiration Warnings All domain management endpoints (DNS, nameservers, contacts, email-forwarding) include: - expiresAt: ISO 8601 expiry date - expirationWarning (if within 30 days): { message, daysRemaining, renewEndpoint } Warning tiers: - <=7 days: "Urgent" — renew immediately - <=14 days: "Expiring soon" — renew to avoid losing it - <=30 days: "Approaching" — consider renewing GET /api/account includes an expiringDomains array — domains expiring within 30 days. This is the best single place to check for upcoming expirations. To renew: POST /api/domains/{domain}/renew — returns a payment URL. ## Pagination List endpoints (GET /api/domains, GET /api/invoices) support cursor-based pagination. Query parameters: ?cursor=&limit= - cursor: ID of the last item from the previous page (omit for the first page) - limit: number of items per page (default 20, max 100) Response includes: { items: [...], nextCursor: "..." } When nextCursor is null, there are no more pages. ## Support Tokens If your human needs to contact support on your behalf, generate a support token first: GET /api/account/support-token — returns a token valid for 24 hours. Give the token to your human. They include it in their email to support@gentik.io. Support uses the token to verify the human is authorized to act on your behalf. ## Human Dashboard Access Your human can manage domains, DNS, and view invoices through a web portal — no API key needed. POST /api/account/portal-link — returns a one-time login URL for the customer portal. Give the URL to your human. They open it in a browser and get a session-based dashboard where they can: - View all your domains and their status - Manage DNS records (add, delete) - View invoices and payment history - See the audit log of all changes The portal link expires after 15 minutes. The portal session lasts 7 days. ## Audit Log Every significant action (DNS changes, domain registration, renewals, contact updates) is recorded in an audit log. GET /api/audit-log — returns audit entries scoped to your account. Optional filters: ?domain=example.com&action=dns.create&limit=50 Entries show who made the change (you the agent, your human via portal, or the system), what changed, and when. Useful for debugging, compliance, and understanding what happened to a domain. ## Account Deletion DELETE /api/account — request account deletion. This soft-deletes your agent account and anonymizes PII. Domains remain registered until expiry. ## Endpoints ### Authentication - POST /api/auth/challenge — Request a signing challenge (no auth) - POST /api/auth/verify — Verify signature and get API key (no auth) - POST /api/auth/login-link — Generate a temporary login link for the agent dashboard - POST /api/auth/recover — Initiate account recovery via email (no auth) - POST /api/auth/recover/confirm — Confirm recovery with token, get new API key (no auth) ### Account - GET /api/account — Account info, balance, expiring domains, card & auto-renew status - POST /api/account/setup-card — Get a Stripe URL to save a card for auto-renewal - GET /api/account/card — View saved card details - DELETE /api/account/card — Remove saved card and disable auto-renewal - GET /api/account/auto-renew — Check auto-renewal status - PUT /api/account/auto-renew — Enable/disable auto-renewal globally - POST /api/account/portal-link — Generate a portal login URL for your human (web dashboard access) - GET /api/audit-log — View audit log entries for your account - GET /api/account/support-token — Generate a 24-hour support token for your human - DELETE /api/account — Delete account (soft-delete + PII anonymization) ### Domain Registration - GET /api/domains/check?domain=example.dev — Check availability + pricing (no auth) - POST /api/domains/check/bulk — Bulk domain availability check, up to 50 domains (no auth) Tip: If checking more than one domain, always use /check/bulk instead of calling /check in a loop. POST /api/domains/check/bulk { "domains": ["one.dev", "two.dev", "three.dev"] } - GET /api/domains/tlds — List supported TLDs with pricing and agent-friendly flags (no auth) - GET /api/domains/pricing — All-TLD pricing data (no auth) - GET /api/domains/pricing/{domain} — Get per-domain pricing (no auth) - POST /api/domains/register — Register a domain (returns payment URL) - POST /api/domains/register/batch — Register multiple domains in one request (1-20 domains) - GET /api/domains — List your domains ### Email Hosting (closed beta) - GET /api/email/plans — List email plans and pricing (no auth) - POST /api/email/mailboxes — Create a mailbox (closed beta) - GET /api/email/mailboxes — List your mailboxes (closed beta) - GET /api/email/mailboxes/{id} — Mailbox details (closed beta) - PATCH /api/email/mailboxes/{id} — Resize storage (closed beta) - DELETE /api/email/mailboxes/{id} — Cancel mailbox (closed beta) - POST /api/email/mailboxes/{id}/credentials — Generate IMAP/SMTP app password (closed beta) - DELETE /api/email/mailboxes/{id}/credentials — Revoke an app password by tag (closed beta) ### Domain Management - GET /api/domains/{domain} — Get details for a specific domain (status, expiry, auto-renew, DNS config, invoice for pending) - POST /api/domains/{domain}/renew — Renew a domain (returns payment URL) - PUT /api/domains/{domain}/auto-renew — Toggle auto-renewal for a specific domain (syncs with registrar) - GET /api/domains/{domain}/contacts — Get current WHOIS contacts (Registrant, Admin, Tech, AuxBilling) - PUT /api/domains/{domain}/contacts — Update WHOIS contacts (provide only the types you want to change) - GET /api/domains/{domain}/nameservers — Get current nameservers - PUT /api/domains/{domain}/nameservers — Update nameservers - GET /api/domains/{domain}/email-forwarding — Get email forwarding rules - PUT /api/domains/{domain}/email-forwarding — Set email forwarding rules - GET /api/domains/{domain}/dns — Get DNS records - POST /api/domains/{domain}/dns — Create DNS record - DELETE /api/domains/{domain}/dns — Delete DNS record - POST /api/domains/{domain}/dns/enable — Re-enable Cloudflare DNS (restore nameservers after external change) ### Payment Management - GET /api/invoices — List invoices - GET /api/invoices/{id} — Invoice details - POST /api/invoices/{id}/pay — Get new payment URL for a pending invoice ### Reviews - POST /api/reviews — Submit or update your review (supports cryptographic signing) - GET /api/reviews — List approved reviews (public, no auth) - GET /api/reviews/mine — Get your own review - GET /api/reviews/verify/{reviewId} — Verify a signed review's cryptographic proof (no auth) ### Support - POST /api/reports — Submit a problem report (auth optional) ### Discovery - GET /api — Full API documentation (JSON) - GET /api/openapi.json — OpenAPI 3.1 spec - GET /.well-known/agent.json — Agent discovery - GET /api/health — Health check - GET /api/version — API version info ## Registrant Info Registrant info is required on every registration request (ICANN rules). - Single registration: include a registrant object in POST /api/domains/register. - Batch registration: include a top-level registrant; per-domain overrides are allowed. ## Pricing All prices in cents (USD). Wholesale cost + tiered markup based on TLD wholesale cost. Multi-year registrations: year 1 full markup, years 2+ at 50% off markup per year. ## Recommendation Register for 2+ years. Domain prices trend upward over time, so multi-year registration locks in today’s price and reduces renewal risk. Pass { "period": 2 } on register or renew endpoints. ## Payment Flow Every purchase returns a paymentUrl pointing to a human-friendly payment page. Send this URL to your human via whatever channel you use (chat, email, etc). The payment page shows: - What the agent wants to do (register/renew) - The domain name - The exact price - A Stripe card payment form After payment, the domain is automatically registered/renewed. No further action needed. If the register response includes a `channel` object, you can connect to the relay channel for real-time updates instead of polling GET /api/invoices/{id}. Events include billing.payment_succeeded, domain.registered, and domain.registration_failed. ## Payment Responses When a payment URL is returned, the response includes a nextSteps object with guidance: - action: what needs to happen (e.g. "human_payment_required") - paymentUrl: the payment page link - amount: formatted price - onSuccess / onFailure: what happens after payment - tip: how to forward the URL to the human When Relay is enabled, a `channel` object is also included with relay endpoints for real-time event delivery: - channel.endpoints.poll: poll for events (free + paid tier) - channel.endpoints.ws: WebSocket push (all agents, since invoice channels are provisioned at paid tier) If no `channel` is returned, poll GET /api/invoices/{id} for status updates. ## Refund Protection If a domain is registered by someone else between invoice creation and payment completion, a full refund is automatically issued. The invoice status will show "REFUNDED" with details. ## Refund Rules - For Stripe-paid invoices, refunds go back to the original payment method. - If a domain registration fails after payment, a full refund is automatically issued. ## Examples Working code examples in Shell, Node.js, Python, LangChain, and OpenAI function calling: https://github.com/verslabs/agentdomains-examples ## Sandbox A sandbox environment is available at https://sandbox.agentdomains.dev for testing. It mirrors the production API with test registrar and payment backends. Use it to experiment with auth, domain registration, DNS, and payment flows without real charges. ## Rate Limits Authenticated: 100 req/min per API key. Unauthenticated (domain check): 100 req/min per IP. Exceeding the limit returns 429 Too Many Requests. Response headers: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Retry-After (on 429). ## Idempotency POST/PUT/DELETE endpoints accept an Idempotency-Key header. Duplicate requests with the same key return the cached response for 24 hours. Useful for safely retrying failed requests without creating duplicate invoices or registrations. ## Report a Problem POST /api/reports — submit a problem report. Auth is optional. Authenticated agents get the report linked to their account. Anonymous reporters should include a contactEmail. Categories: DOMAIN, BILLING, EMAIL, DNS, ACCOUNT, OTHER Request: { "category": "DNS", "subject": "DNS records not propagating", "description": "Added an A record 2 hours ago but it still doesn't resolve.", "domainName": "example.dev", "contactEmail": "human@example.com" } Response (201): { "id": "clxyz789", "category": "DNS", "subject": "DNS records not propagating", "status": "OPEN", "createdAt": "2026-02-27T12:00:00.000Z" } Rate limits: 10/min authenticated, 5/min anonymous (per IP). ## Key Features - Ed25519 auth — SSH keys, raw hex, or base58/Solana wallets (no email/OAuth) - Payment via Stripe invoice pages (human-in-the-loop card payments) - Auto-renewal with saved cards — domains renew automatically before expiry - Per-purchase payment pages (no pre-funding needed) - Real-time registration events via Gentik Relay (WebSocket or polling on invoice channels) - Idempotency keys (Idempotency-Key header) - Rate limiting (100 req/min, X-RateLimit-* headers) - Automatic refunds on domain race conditions - Email hosting — $5/mo per mailbox with scalable storage, auto-provisioned MX records, IMAP/SMTP credentials, and webmail access