{"openapi":"3.1.0","x-id":["public"],"info":{"title":"ird API","description":"Public API for ird services. Authenticate with an API key created in your account panel (`Authorization: Bearer ird_...`) or with an account JWT obtained via the `ird login` device flow. Work is submitted as asynchronous jobs: enqueue, poll for status, then fetch the result. Submitted content is never persisted; results are kept for 24 hours.","version":"1.0.0"},"servers":[{"url":"https://api.ird.ro"}],"tags":[{"name":"jobs","description":"Asynchronous processing jobs (API-key authenticated)"},{"name":"domains","description":"Domain availability search and utilities (anonymous allowed; higher rate limits with an API key)"},{"name":"directory","description":"The classified .ro web directory (API key or account JWT)"},{"name":"registrations","description":"Register, renew, transfer and manage .ro domains (API key or account JWT; complete customer profile required — registrations charge 65 credits/year up front, refunded on failure)"},{"name":"vps","description":"EU cloud servers: tiers, SSH keys, instances, volumes, snapshots (API key or account JWT; complete customer profile required — hourly prepaid credit billing until destroy, reads charge vps.reads)"},{"name":"tunnels","description":"HTTPS tunnels on your own domain, reverse-tunneled to your device over SSH (API key or account JWT; complete customer profile required — hourly billing while the tunnel exists, overdraft allowed, reads charge tunnel.reads)"},{"name":"ipfs","description":"IPFS pinning, direct uploads, IPNS names and customer gateway domains (API key or account JWT; complete customer profile required — prepaid hourly billing per pinned MiB plus gateway egress, reads charge ipfs.reads, deletes are always free). The standard IPFS Pinning Service API 1.0.0 is served at /pins, so `ipfs pin remote service add ird https://api.ird.ro ird_...` works out of the box"},{"name":"support","description":"Support conversations with the ird team (API key or account JWT; 0-priced at launch and overdraft-allowed — support stays reachable even at a negative balance)"},{"name":"credits","description":"Usage pricing, your balance and ledger history (1 credit = 1 RON)"},{"name":"sharing","description":"Delegated domain access: an owner grants another customer scoped management of a domain (dns/tunnel/ipfs/vps), with charges billed per the share's payer setting — the owner by default, the grantee, or split half-and-half (account JWT only; invites demand a fresh authenticator code)"},{"name":"transfers","description":"Account-to-account VPS handovers: servers (with attached volumes), standalone volumes and images move with their hourly billing once the recipient accepts (account JWT only; offer and accept demand a fresh authenticator code)"},{"name":"api-keys","description":"API key management (account JWT authenticated)"},{"name":"auth","description":"Device-authorization login (`ird login`): obtain an account JWT session by approving a code in the browser"}],"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"ird_...","description":"API key created in the account panel, e.g. `Authorization: Bearer ird_XR2X...`"},"accountJwt":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Account access token from the login flow or `ird login` device authorization — a first-class public-API credential; refresh it at `/auth/refresh`. Sessions are listed and revocable in the account panel."}}},"paths":{"/contact/threads":{"get":{"parameters":[{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}},{"in":"query","name":"cursor","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Support threads (`next_cursor` present while more may remain)","content":{"application/json":{"schema":{"type":"object","properties":{"threads":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"service":{"oneOf":[{"type":"string","enum":["domains","consultancy","spatial","general"]},{"type":"null"}]},"last_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"message_count":{"type":"integer"},"unread_count":{"type":"integer"},"last_preview":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_activity_at":{"type":"string"}},"required":["id","email","title","service","last_name","message_count","unread_count","last_preview","created_at","updated_at","last_activity_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]},"unread_count":{"type":"integer"}},"required":["threads","next_cursor","unread_count"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["support"],"summary":"List your support threads","description":"Your support conversations with the ird team, newest first (threads are keyed by account email), plus `unread_count` — how many team replies and team-opened messages you haven't read yet. The ird team can also open a thread with you (an announcement or a direct message): its first message carries `author` `team`. Keyset-paginated: pass the previous page's `next_cursor` as `cursor` (`limit` defaults to 50, capped at 200); `next_cursor` is null once no further page can exist. 0-priced at launch (contract `support.reads` — see GET /credits/prices); overdraft is always allowed, so support stays reachable even at a negative balance.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"service":{"type":"string","enum":["domains","consultancy","spatial","general"]},"message":{"type":"string","minLength":1,"maxLength":5000}},"required":["title","service","message"],"additionalProperties":false}}}},"responses":{"200":{"description":"Thread opened","content":{"application/json":{"schema":{"type":"object","properties":{"thread":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"service":{"oneOf":[{"type":"string","enum":["domains","consultancy","spatial","general"]},{"type":"null"}]},"last_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"message_count":{"type":"integer"},"unread_count":{"type":"integer"},"last_preview":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_activity_at":{"type":"string"}},"required":["id","email","title","service","last_name","message_count","unread_count","last_preview","created_at","updated_at","last_activity_at"],"additionalProperties":false}},"required":["thread"],"additionalProperties":false}}}},"400":{"description":"Missing or invalid title, service, or message","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["support"],"summary":"Open a support thread","description":"Starts a conversation with the ird team: a title, the service it concerns (`domains`, `consultancy`, `spatial`, or `general`), and your message. Replies from the team arrive asynchronously — poll `GET /contact/threads/{id}` or watch `unread_count` on the list; they are also emailed to your account address, and answering that email appends to the same thread. 0-priced at launch (contract `support.writes` — see GET /credits/prices); overdraft is always allowed, so support stays reachable even at a negative balance.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/contact/threads/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Thread with messages and replies","content":{"application/json":{"schema":{"type":"object","properties":{"thread":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"service":{"oneOf":[{"type":"string","enum":["domains","consultancy","spatial","general"]},{"type":"null"}]},"last_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"message_count":{"type":"integer"},"unread_count":{"type":"integer"},"last_preview":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_activity_at":{"type":"string"}},"required":["id","email","title","service","last_name","message_count","unread_count","last_preview","created_at","updated_at","last_activity_at"],"additionalProperties":false},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"thread_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"},"email":{"type":"string"},"message":{"type":"string"},"user_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"string","enum":["customer","team"]},"created_at":{"type":"string"},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"display_name":{"type":"string"},"body":{"type":"string"},"created_at":{"type":"string"}},"required":["id","display_name","body","created_at"],"additionalProperties":false}}},"required":["id","thread_id","name","email","message","user_id","author","created_at","replies"],"additionalProperties":false}}},"required":["thread","messages"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["support"],"summary":"Read a support thread","description":"One of your threads with every message and every ird-team reply, chronological; each message's `author` is `customer` (you) or `team` (a thread the ird team opened with you). Reading marks the thread's replies as seen (resets its `unread_count`). 0-priced at launch (contract `support.reads`).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/contact/threads/{id}/messages":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":5000}},"required":["message"],"additionalProperties":false}}}},"responses":{"200":{"description":"Refreshed thread with messages and replies","content":{"application/json":{"schema":{"type":"object","properties":{"thread":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"service":{"oneOf":[{"type":"string","enum":["domains","consultancy","spatial","general"]},{"type":"null"}]},"last_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"message_count":{"type":"integer"},"unread_count":{"type":"integer"},"last_preview":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"updated_at":{"type":"string"},"last_activity_at":{"type":"string"}},"required":["id","email","title","service","last_name","message_count","unread_count","last_preview","created_at","updated_at","last_activity_at"],"additionalProperties":false},"messages":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"thread_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"name":{"type":"string"},"email":{"type":"string"},"message":{"type":"string"},"user_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"author":{"type":"string","enum":["customer","team"]},"created_at":{"type":"string"},"replies":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"display_name":{"type":"string"},"body":{"type":"string"},"created_at":{"type":"string"}},"required":["id","display_name","body","created_at"],"additionalProperties":false}}},"required":["id","thread_id","name","email","message","user_id","author","created_at","replies"],"additionalProperties":false}}},"required":["thread","messages"],"additionalProperties":false}}}},"400":{"description":"Missing or too-long message","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["support"],"summary":"Reply on a support thread","description":"Appends your message to one of your threads and returns the refreshed conversation. 0-priced at launch (contract `support.writes`).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/credits/balance":{"get":{"responses":{"200":{"description":"Current balances","content":{"application/json":{"schema":{"type":"object","properties":{"balances":{"type":"array","items":{"type":"object","properties":{"credit_type":{"type":"string"},"balance":{"type":"string"}},"required":["credit_type","balance"],"additionalProperties":false}},"total":{"type":"string"},"spend":{"type":"object","properties":{"window_days":{"type":"integer"},"total":{"type":"string"},"avg_per_day":{"type":"string"},"runway_days":{"oneOf":[{"type":"integer"},{"type":"null"}]}},"required":["window_days","total","avg_per_day","runway_days"],"additionalProperties":false}},"required":["balances","total","spend"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["credits"],"summary":"Credit balance","description":"The authenticated account's current balance per credit type plus the total, and a spend summary over the last 30 complete Europe/Bucharest calendar days: total spend (charges net of refunds), average per day, and `runway_days` — how many days the current balance sustains that average (null when there is no recent spend). Amounts are exact decimal strings (1 credit = 1 RON). Free to call — reading your own balance is never charged.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/credits/ledger":{"get":{"parameters":[{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"Page size, capped at 200"},{"in":"query","name":"cursor","required":false,"schema":{"type":"integer"},"description":"Opaque `seq` cursor from a previous page's `next_cursor`"},{"in":"query","name":"type","required":false,"schema":{"type":"string"},"description":"Filter by credit type"},{"in":"query","name":"kind","required":false,"schema":{"type":"string","enum":["grant","purchase","charge","adjustment","refund","expiry"]}},{"in":"query","name":"contract","required":false,"schema":{"type":"string"},"description":"Filter by the contract that produced the charge (dotted form, e.g. `domains.search`); empty string matches entries without one"},{"in":"query","name":"resource","required":false,"schema":{"type":"string"},"description":"Filter by the id of the resource a recurring charge bills (the `resource.id` of an entry); empty string matches entries without one"},{"in":"query","name":"day","required":false,"schema":{"type":"string"},"description":"Restrict to one statement day (ISO date, Europe/Bucharest)"}],"responses":{"200":{"description":"Ledger entries, newest first","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"credit_type":{"type":"string"},"amount":{"type":"string"},"kind":{"type":"string","enum":["grant","purchase","charge","adjustment","refund","expiry"]},"reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"balance_after":{"type":"string"},"created_at":{"type":"string"},"invoice_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource":{"description":"The resource a recurring (hourly) charge bills: its type (e.g. `dns/hosted-zone`, `dns/zone`, `vps/instance`), id, and a label when it has one (the hosted zone's domain).","type":"object","properties":{"type":{"oneOf":[{"type":"string"},{"type":"null"}]},"id":{"oneOf":[{"type":"string"},{"type":"null"}]},"label":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["type","id","label"],"additionalProperties":false}},"required":["id","seq","credit_type","amount","kind","reason","balance_after","created_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"integer"},{"type":"null"}]}},"required":["entries","next_cursor"],"additionalProperties":false}}}},"400":{"description":"Invalid filter parameters","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["credits"],"summary":"Credit ledger history","description":"The authenticated account's append-only ledger history, newest first, cursor-paginated on `seq`. Every grant, purchase, charge, adjustment, refund, and expiry is an entry; charges carry the contract they settled. Amounts are exact decimal strings (1 credit = 1 RON). Free to call — reading your own history is never charged.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/credits/prices":{"get":{"responses":{"200":{"description":"Active price book version","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"integer"},"created_at":{"type":"string"},"prices":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"pending":{"description":"The scheduled price book version, present only while one is waiting to take effect. Charges keep using the active `prices` until `effective_at`.","type":"object","properties":{"version":{"type":"integer"},"effective_at":{"description":"ISO-8601 instant (UTC) at which `pending.prices` replace the active ones.","type":"string"},"prices":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{}}},"diff":{"description":"Row-level differences between the active and the pending document: one row per price key (or nested sub-key) that changes, appears or disappears.","type":"array","items":{"type":"object","properties":{"contract":{"type":"string"},"key":{"type":"string"},"sub_key":{"oneOf":[{"type":"string"},{"type":"null"}]},"old":{"oneOf":[{"type":"string"},{"type":"null"}]},"new":{"oneOf":[{"type":"string"},{"type":"null"}]},"change":{"type":"string","enum":["changed","new","removed"]},"percent":{"description":"Relative change of `new` against `old` as a decimal string (e.g. `-12.5`); null for new or removed keys.","oneOf":[{"type":"string"},{"type":"null"}]}},"required":["contract","key","sub_key","old","new","change","percent"],"additionalProperties":false}}},"required":["version","effective_at","prices","diff"],"additionalProperties":false},"registrar":{"description":"Purchase constraints that travel with the price book, so a client can size its year selectors from the same call that prices them.","type":"object","properties":{"max_years":{"description":"The admin-tunable cap on `years` in a single register, renew, transfer-in or trade order; above it those endpoints answer 400. It bounds ONE order, not how far ahead a domain may be held — at a cap of 1, nine consecutive renewals still carry a domain nine years forward. At most 10.","type":"integer"}},"required":["max_years"],"additionalProperties":false}},"required":["version","created_at","prices","registrar"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["credits"],"summary":"Current usage prices","description":"The active price book: what each endpoint and job type costs in credits (1 credit = 1 RON). Charges use the version effective at charge time (hourly recurring periods: the version effective at the period start); every ledger charge records the version and prices it was computed with. A scheduled version is exposed under `pending` until it takes effect. Amounts are exact decimal strings. Requires an API key or account JWT — no complete billing profile needed.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/check":{"get":{"parameters":[{"in":"query","name":"domain","required":true,"schema":{"type":"string","minLength":3,"maxLength":255}}],"responses":{"200":{"description":"Availability result","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"tld":{"type":"string"},"status":{"type":"string","enum":["available","registered","reserved","unknown"]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"oneOf":[{"type":"array","items":{"type":"string"}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["domain","tld","status","expires_at","nameservers","checked_at"],"additionalProperties":false}}}},"400":{"description":"Invalid domain name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limit exceeded for your tier","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"502":{"description":"Registry lookup failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Registry unavailable or TLD not supported","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["domains"],"summary":"Check domain availability","description":"Checks whether a domain can be registered (.ro only for now). Works without authentication at a low per-IP rate limit; authenticated accounts and API keys get higher limits. Answers are cached — available domains are re-verified against the registry after 5 minutes, taken domains after 24 hours (15 minutes when close to expiry). `served_from` says how the answer was produced.","security":[{},{"apiKey":[]}]}},"/domains/info":{"get":{"parameters":[{"in":"query","name":"domain","required":true,"schema":{"type":"string","minLength":3,"maxLength":255}},{"in":"query","name":"fields","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain information (only the requested fields are present)","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"tld":{"type":"string"},"whois":{"type":"object","additionalProperties":{}},"dns":{"type":"object","additionalProperties":{}},"subdomains":{"type":"object","additionalProperties":{}},"registry":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]}},"required":["domain","tld"],"additionalProperties":false}}}},"400":{"description":"Invalid domain name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limit exceeded for your tier","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["domains"],"summary":"Domain information utilities","description":"Gathers public information about any domain: WHOIS record, live DNS records (NS/A/AAAA/MX/TXT/SOA), and — opt-in — subdomains observed in Certificate Transparency logs (crt.sh). For .ro domains a `registry` block adds ROTLD data (expiry, nameservers). `fields` is a comma list of `whois`, `dns`, `subdomains` (default `dns,whois`). Requires authentication — an API key or an account JWT; no anonymous tier.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/preflight":{"get":{"parameters":[{"in":"query","name":"domain","required":true,"schema":{"type":"string","minLength":3,"maxLength":255}}],"responses":{"200":{"description":"The routing verdict","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"verdict":{"type":"string","enum":["adopt","trade-in","transfer-or-acquire","register","already-yours","unavailable","unknown"]},"sponsorship":{"oneOf":[{"type":"string","enum":["ird","external","unregistered","unknown"]},{"type":"null"}]},"registrant_controlled":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["domain","verdict","sponsorship","registrant_controlled","registrant_email_hint","expires_at","registration_id"],"additionalProperties":false}}}},"400":{"description":"Invalid or non-.ro domain","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limit exceeded for your tier","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["domains"],"summary":"Route a domain to the right inbound operation","description":"Decides, before anything is enqueued or charged, which operation brings `domain` into your account: `adopt` (already sponsored by ird and the registrant email is an address you control — no registry operation needed), `trade-in` (already sponsored by ird, registrant is someone else — you need an ownership change, not a transfer), `transfer-or-acquire` (sponsored by another registrar), `register` (not registered at all), `already-yours` / `unavailable` (a live registration exists), or `unknown` (the registry probe could not decide — fall back to the manual forms; a transfer or trade can still be submitted). `registrant_email_hint` is a masked hint (`j***@e***.ro`), never the full address. Requires an API key or an account JWT.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/dns-snapshot":{"get":{"parameters":[{"in":"query","name":"domain","required":true,"schema":{"type":"string","minLength":3,"maxLength":255}},{"in":"query","name":"subdomains","required":false,"schema":{"type":"string","enum":["true","false"]}},{"in":"query","name":"names","required":false,"schema":{"type":"string","maxLength":4096}}],"responses":{"200":{"description":"The captured DNS copy","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"nameservers":{"type":"array","items":{"type":"string"}},"records":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"ttl":{"type":"integer"},"data":{"type":"object","additionalProperties":{}}},"required":["name","type","class","ttl","data"],"additionalProperties":false}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"taken_at":{"type":"string"}},"required":["id","domain","tld","nameservers","records","meta","taken_at"],"additionalProperties":false}}}},"400":{"description":"Invalid domain name or names list","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limit exceeded for your tier","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"502":{"description":"The capture failed (resolvers unreachable / timed out) — not billed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["domains"],"summary":"Faithful copy of a domain's live DNS","description":"Captures a point-in-time copy of a domain's live DNS straight from its authoritative nameservers (authentic TTLs; a whole-zone transfer is attempted first, falling back to probing the apex and common subdomain labels across A/AAAA/CNAME/MX/TXT/SRV/CAA plus NS/SOA at the apex). `subdomains=true` additionally probes subdomains observed in Certificate Transparency logs (crt.sh) — slower and priced separately (see `GET /credits/prices`, contract `domains.dns-snapshot`). `names` lists extra subdomains to probe beyond the common labels — comma-separated bare labels (`intranet`) or full names under the domain (`vpn.office.example.ro`), at most 38 per call, at no extra cost; every probed subdomain also gets its wildcard sibling (`*.name`) checked, and the apex wildcard (`*.example.ro`) is always probed. Works for any domain, not just ones registered through ird; the copy is persisted and `meta` describes how it was made (`axfr?`, `authoritative?`, per-query errors). Requires an API key or an account JWT.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/search":{"get":{"parameters":[{"in":"query","name":"q","required":true,"schema":{"type":"string","minLength":1}},{"in":"query","name":"count","required":false,"schema":{"type":"integer","minimum":1,"maximum":15}}],"responses":{"200":{"description":"Suggestions with availability","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"suggestions":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string"},"tld":{"type":"string"},"status":{"type":"string","enum":["available","registered","reserved","unknown"]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"served_from":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"type":"string"}},"required":["domain","tld","status","expires_at","served_from"],"additionalProperties":false}}},"required":["query","suggestions"],"additionalProperties":false}}}},"400":{"description":"Missing or invalid q","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Suggestion rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"502":{"description":"LLM generation failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Suggestions unavailable (LLM service not configured or down)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["domains"],"summary":"Suggest available domain names","description":"Generates new .ro domain name ideas from a free-form query — a domain, a phrase, or a description of what you're building — using an LLM, then checks each suggestion's availability. Synchronous; expect a few seconds. Requires an API key or account JWT, with stricter rate limits than the other domain endpoints. `served_from` says how each availability answer was produced; suggestions that could not be checked carry `status: unknown` plus an `error` code. For long descriptions use the POST form — a GET query string is capped by URL length.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"q":{"type":"string","minLength":1},"count":{"type":"integer","minimum":1,"maximum":15}},"required":["q"],"additionalProperties":false}}}},"responses":{"200":{"description":"Suggestions with availability","content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string"},"suggestions":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string"},"tld":{"type":"string"},"status":{"type":"string","enum":["available","registered","reserved","unknown"]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"served_from":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"type":"string"}},"required":["domain","tld","status","expires_at","served_from"],"additionalProperties":false}}},"required":["query","suggestions"],"additionalProperties":false}}}},"400":{"description":"Missing or invalid q","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Suggestion rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"502":{"description":"LLM generation failed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Suggestions unavailable (LLM service not configured or down)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["domains"],"summary":"Suggest available domain names (long descriptions)","description":"Identical to GET /domains/search, but the query rides the request body — use this form for long project descriptions that do not fit a URL. `q` is bounded only by the suggestion model's context window (default 750,000 characters, deployment-tunable). Same auth, rate limits, and pricing.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/example":{"get":{"responses":{"200":{"description":"Example domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"}},"required":["domain"],"additionalProperties":false}}}},"404":{"description":"No example available yet (the pool is still empty)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limit exceeded for your tier","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["domains"],"summary":"Example .ro domain","description":"Returns a generated example Romanian personal domain (a name or nickname under .ro), used as the rotating placeholder in the domain search box. Each name is served once; successive requests work through the whole pool before anything repeats.","security":[{},{"apiKey":[]}]}},"/domains/directory":{"get":{"parameters":[{"in":"query","name":"category","required":false,"schema":{"type":"string","enum":["news-media","government","education","health","e-commerce","business-services","finance","technology","travel-tourism","real-estate","auto","legal","culture-arts","sports","entertainment","food-restaurants","religion","ngo-nonprofit","blog-personal","adult","gambling","parked-for-sale","other"]}},{"in":"query","name":"tag","required":false,"schema":{"type":"string","minLength":2,"maxLength":60}},{"in":"query","name":"bias","required":false,"schema":{"type":"string","enum":["left","center-left","center","center-right","right"]}},{"in":"query","name":"sentiment","required":false,"schema":{"type":"string","enum":["positive","neutral","negative","mixed"]}},{"in":"query","name":"language","required":false,"schema":{"type":"string","minLength":2,"maxLength":8}},{"in":"query","name":"ad_network","required":false,"schema":{"type":"string","minLength":2,"maxLength":40}},{"in":"query","name":"tracker","required":false,"schema":{"type":"string","minLength":2,"maxLength":40}},{"in":"query","name":"tag_manager","required":false,"schema":{"type":"string","minLength":2,"maxLength":40}},{"in":"query","name":"cookie_consent","required":false,"schema":{"type":"string","enum":["true","false"]}},{"in":"query","name":"q","required":false,"schema":{"type":"string","minLength":2,"maxLength":100}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}},{"in":"query","name":"cursor","required":false,"schema":{"type":"string"}},{"in":"query","name":"offset","required":false,"schema":{"type":"integer","minimum":0,"maximum":10000}},{"in":"query","name":"include_total","required":false,"schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Directory page (`next_cursor` present while more results remain; `total` present when include_total=true)","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"domain":{"type":"string"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"language":{"oneOf":[{"type":"string"},{"type":"null"}]},"categories":{"type":"array","items":{"type":"string","enum":["news-media","government","education","health","e-commerce","business-services","finance","technology","travel-tourism","real-estate","auto","legal","culture-arts","sports","entertainment","food-restaurants","religion","ngo-nonprofit","blog-personal","adult","gambling","parked-for-sale","other"]}},"tags":{"type":"array","items":{"type":"string"}},"political_bias":{"oneOf":[{"type":"string","enum":["left","center-left","center","center-right","right"]},{"type":"null"}]},"sentiment":{"oneOf":[{"type":"string","enum":["positive","neutral","negative","mixed"]},{"type":"null"}]},"contacts":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"ad_networks":{"type":"array","items":{"type":"string"}},"trackers":{"type":"array","items":{"type":"string"}},"tag_managers":{"type":"array","items":{"type":"string"}},"cookie_consent":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"cookie_consent_platform":{"oneOf":[{"type":"string"},{"type":"null"}]},"first_seen_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"classified_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["domain","title","description","language","categories","tags","political_bias","sentiment","contacts","ad_networks","trackers","tag_managers","cookie_consent","cookie_consent_platform","first_seen_at","classified_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]},"total":{"type":"integer"}},"required":["entries","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["directory"],"summary":"Browse the .ro web directory","description":"Classified directory of .ro websites discovered by our crawler. Each entry carries LLM-derived metadata (categories, topic tags, political bias, sentiment, language, contacts, description) plus deterministically detected technology signals: ad networks (`ad_networks`), analytics/tracking libraries (`trackers`), tag managers (`tag_managers` — when present, the ad/tracker lists may undercount tags injected at runtime), and whether the site shows a cookie-consent banner (`cookie_consent`, with `cookie_consent_platform` naming the CMP when recognized). Filters compose with AND; `q` searches domain names and descriptions. Pagination is keyset: pass `next_cursor` from the previous page as `cursor`. Requires an API key or an account JWT.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/directory/{domain}":{"get":{"parameters":[{"in":"path","name":"domain","required":true,"schema":{"type":"string","minLength":3,"maxLength":255}}],"responses":{"200":{"description":"Directory entry","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"title":{"oneOf":[{"type":"string"},{"type":"null"}]},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"language":{"oneOf":[{"type":"string"},{"type":"null"}]},"categories":{"type":"array","items":{"type":"string","enum":["news-media","government","education","health","e-commerce","business-services","finance","technology","travel-tourism","real-estate","auto","legal","culture-arts","sports","entertainment","food-restaurants","religion","ngo-nonprofit","blog-personal","adult","gambling","parked-for-sale","other"]}},"tags":{"type":"array","items":{"type":"string"}},"political_bias":{"oneOf":[{"type":"string","enum":["left","center-left","center","center-right","right"]},{"type":"null"}]},"sentiment":{"oneOf":[{"type":"string","enum":["positive","neutral","negative","mixed"]},{"type":"null"}]},"contacts":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"ad_networks":{"type":"array","items":{"type":"string"}},"trackers":{"type":"array","items":{"type":"string"}},"tag_managers":{"type":"array","items":{"type":"string"}},"cookie_consent":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"cookie_consent_platform":{"oneOf":[{"type":"string"},{"type":"null"}]},"first_seen_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"classified_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["domain","title","description","language","categories","tags","political_bias","sentiment","contacts","ad_networks","trackers","tag_managers","cookie_consent","cookie_consent_platform","first_seen_at","classified_at"],"additionalProperties":false}}}},"400":{"description":"Invalid domain name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["directory"],"summary":"Directory entry for a domain","description":"The classified directory record for one .ro domain. 404 when the domain has not been discovered and classified (yet). Requires an API key or an account JWT.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations":{"get":{"parameters":[{"in":"query","name":"cursor","required":false,"schema":{"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Registrations","content":{"application/json":{"schema":{"type":"object","properties":{"registrations":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["registrations","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"List your domains","description":"Registrations newest first; paginate with `cursor` (the ISO-8601 `next_cursor` of the previous page). `expired` is derived — a domain past expiry stays renewable through the registry grace window. Charged per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"years":{"type":"integer","minimum":1,"maximum":10},"nameservers":{"type":"array","items":{"type":"string"}},"use_our_dns":{"type":"boolean"},"auto_renew":{"type":"boolean"}},"required":["domain","years"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — charged up front, executing asynchronously","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["registration","action"],"additionalProperties":false}}}},"400":{"description":"Invalid domain, years, or nameservers","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Domain unavailable or already has a live registration","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Register a .ro domain","description":"Enqueue a registration. The full price (65 credits/year at launch — see GET /credits/prices, `domains.register`) is charged up front and refunded automatically if the registration terminally fails. Registrations execute strictly in order; poll the returned action. Requires a complete customer profile. `years` is capped at the current per-order maximum (`registrar.max_years` on GET /credits/prices, at most 10); above it the request answers 400. `use_our_dns` hosts the domain's DNS on the ird nameservers: once the registration lands, the zone is provisioned automatically and the registry is pointed at it. Mutually exclusive with explicit `nameservers`.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Registration + recent actions","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false},"actions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}}},"required":["registration","actions"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Get a domain","description":"One registration with its recent registry actions. Charged per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/renew":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"years":{"type":"integer","minimum":1,"maximum":10},"totp_code":{"type":"string"}},"required":["years"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid years","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, or a renewal is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Renew a domain","description":"Enqueue a renewal (65 credits/year at launch, charged up front, refunded on terminal failure). Renewable while active, including the post-expiry grace window. `years` is capped at the current per-order maximum (`registrar.max_years` on GET /credits/prices, at most 10).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/auto-renew":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"totp_code":{"type":"string"}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"description":"Updated registration","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Toggle auto-renew","description":"Auto-renew enqueues a 1-year renewal about 30 days before expiry, charged like a manual renewal (you are emailed if credits run short). Synchronous — no registry involvement.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/sensitive":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"totp_code":{"type":"string"}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"description":"Updated registration","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Toggle the sensitive-domain protection","description":"Marks the domain sensitive: every mutation touching it — registrar operations, hosted DNS changes, tunnels on its hostnames — then demands a fresh authenticator (or backup) code in `totp_code`, and API-key callers are refused outright. The toggle itself is session-only (403 sensitive-domain-api-key-blocked with an API key, in either direction). Enabling is immediate; disabling is itself a sensitive mutation, so it also requires `totp_code`. Synchronous — no registry involvement.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/nameservers":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"nameservers":{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":6},"totp_code":{"type":"string"}},"required":["nameservers"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid nameservers","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"A nameserver change is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Replace nameservers","description":"Enqueue a wholesale nameserver replacement (2–6 hostnames). Small per-change fee, charged up front.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/hosts":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"refresh","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"Host objects under the domain","content":{"application/json":{"schema":{"type":"object","properties":{"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}},"usage_count":{"oneOf":[{"type":"integer"},{"type":"null"}]},"statuses":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}}},"required":["hosts"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"List the domain's hosts (glue records)","description":"The host objects registered under this domain at the registry — e.g. ns1.<domain> with its IPs, created so the domain (or any other .ro domain) can delegate to it. Served from the last-known mirror; `refresh=true` re-reads every host from the registry and adds `usage_count` (how many .ro domains delegate to it — deletion is blocked while it is above zero) and `statuses`. Charged per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":2},"totp_code":{"type":"string"}},"required":["host","ips"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid host name or IPs","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, host already exists, host cap reached, or a host creation is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Create a host (glue record)","description":"Enqueue a host-object creation at the registry: `host` must be a subdomain of the domain itself (e.g. ns1.<domain> — IDN labels in punycode xn-- form), `ips` are 1–2 IPv4/IPv6 literals. Once created, the host can serve as a nameserver for any .ro domain. At most 6 hosts per domain. Small per-change fee, charged up front and refunded on terminal failure; poll the returned action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/hosts/{host}":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"host","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ips":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":2},"totp_code":{"type":"string"}},"required":["ips"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid host name or IPs","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, or a host update is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Replace a host's IPs","description":"Enqueue an IP replacement for the host — the registry replaces the IP set wholesale with `ips` (1–2 IPv4/IPv6 literals). Small per-change fee, charged up front and refunded on terminal failure; poll the returned action.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"host","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid host name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, or a host deletion is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Delete a host (glue record)","description":"Enqueue a host-object deletion. The registry refuses while other .ro domains still delegate to the host (check `usage_count` on the refreshed list first) — the action then fails with the registry's message and the fee is refunded. Small per-change fee, charged up front; poll the returned action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/dsdata":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"refresh","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"description":"DS records published for the domain","content":{"application/json":{"schema":{"type":"object","properties":{"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}}},"required":["dsdata"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"List the domain's DS records","description":"The DNSSEC delegation signer (DS) records published at the registry for this domain — what makes validating resolvers trust the zone's DNSKEY. Served from the last-known mirror; `refresh=true` re-reads the registry's DSDATA (a full read-back) and rewrites the mirror. Charged per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"},"totp_code":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid DS fields","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, no nameservers, duplicate DS, cap reached, or a DS publish is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Publish a DS record","description":"Enqueue publishing a DNSSEC DS record at the registry: `keytag` (0–65535), `alg` (3, 5–8, 10, 12–14), `digest_type` (1 = SHA-1, 2 = SHA-256) and the hex `digest` (40 or 64 characters). The domain must have nameservers at the registry, and at most 4 DS records fit (registry limit). WARNING: a DS that does not match a DNSKEY served by the zone makes the domain unresolvable for validating resolvers. Small per-change fee, charged up front and refunded on terminal failure; poll the returned action.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"},"totp_code":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid DS fields","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Registration or DS record not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, or a DS withdrawal is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Withdraw a DS record","description":"Enqueue withdrawing the DS record matching the body's full 4-tuple (`keytag`, `alg`, `digest_type`, `digest`) from the registry. The tuple travels in the body because it is the record's whole identity. WARNING: withdrawing the last DS makes the delegation insecure (but resolvable); withdrawing a DS while the zone still expects validation can leave stale trust — remove DS records before unsigning the zone, never after. Small per-change fee, charged up front and refunded on terminal failure; poll the returned action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/transfer-out":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Intent recorded","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false},"instructions":{"type":"string"}},"required":["registration","instructions"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Registration not active","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Start moving a domain away","description":"Records your intent and disables auto-renew. The transfer authorization key comes from the registry's own registrant key-recovery flow (ROTLD emails the registrant) — there is no registrar-side key. The domain stays active and renewable until the receiving registrar completes the transfer.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/dns":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"ttl":{"oneOf":[{"type":"integer"},{"type":"null"}]},"data":{"type":"object","additionalProperties":{}}},"required":["name","type","class","ttl","data"],"additionalProperties":false}},"default_ttl":{"type":"integer"},"apply_registry_ns":{"type":"boolean"},"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"202":{"description":"Zone provisioned (registry NS change enqueued unless disabled or listed in registry_error)","content":{"application/json":{"schema":{"type":"object","properties":{"origin":{"type":"string"},"nameservers":{"type":"array","items":{"type":"string"}},"nameservers_mode":{"type":"string","enum":["shared","labels"]},"nameservers_ready":{"type":"boolean"},"zones":{"type":"array","items":{"type":"object","properties":{"origin":{"type":"string"},"node":{"type":"string"},"default_ttl":{"type":"integer"},"nameservers":{"type":"array","items":{"type":"string"}},"created_at":{"type":"string"}},"required":["origin","node","default_ttl","nameservers","created_at"],"additionalProperties":false}},"registry_action":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"registry_error":{"type":"string"}},"required":["origin","nameservers","nameservers_mode","nameservers_ready","zones","registry_action"],"additionalProperties":false}}}},"503":{"description":"DNS hosting not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Registration is not active","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"400":{"description":"Invalid records","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Put a domain on ird nameservers","description":"Provisions the domain's DNS zone on the ird nameservers, optionally seeded with `records`, and — unless `apply_registry_ns` is false — enqueues the registrar nameserver change pointing the registry at the zone's NS set (that action is charged `domains.nameservers` as usual and appears in the response as `registry_action`). Re-provisioning replaces the zone's records wholesale. `nameservers_mode` says which set the zone got: `shared` (ird's public nameservers) or `labels` (the zone's own private nameservers `<label>.nN.<ns domain>` — the default for .ro domains; ird's infrastructure domains always stay on the shared set, and so does a zone provisioned while the private nameservers could not be built — see `GET …/dns/nameservers` to move it later). With `labels`, the registry needs the private nameservers to exist as host objects first: ird creates them and applies the registry NS change only once they do, so `nameservers_ready` may start false — poll `GET …/dns/nameservers`. See `GET /credits/prices` (contract `dns.provision`).","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Zone decommissioned","content":{"application/json":{"schema":{"type":"object","properties":{"decommissioned":{"type":"boolean"},"snapshot_id":{"type":"string"},"zones_deleted":{"type":"integer"}},"required":["decommissioned","snapshot_id","zones_deleted"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Registration or hosted zone not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"DNS hosting not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Take a domain off ird DNS","description":"Removes the domain's hosted zone from the ird nameservers. The zone's records are saved as a DNS snapshot first, so the setup can be reconstructed later. The registry nameservers are NOT changed — point them elsewhere first or the domain stops resolving.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/dns/nameservers":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The zone's nameserver mode","content":{"application/json":{"schema":{"type":"object","properties":{"origin":{"type":"string"},"mode":{"type":"string","enum":["shared","labels"]},"nameservers":{"type":"array","items":{"type":"string"}},"nameservers_ready":{"type":"boolean"},"available_modes":{"type":"array","items":{"type":"string","enum":["shared","labels"]}}},"required":["origin","mode","nameservers","nameservers_ready","available_modes"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Registration or hosted zone not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Which nameservers the hosted zone uses","description":"The nameserver set the domain's hosted zone is published under: `shared` — ird's public nameservers, the same for every zone — or `labels` — the zone's own private nameservers `<label>.nN.<ns domain>`, unique to this domain and account. `nameservers_ready` is true when the registry can be pointed at the set right now; for `labels` it stays false until ird has created the private nameservers as host objects at the registry (a .ro requirement), which happens automatically within minutes. `available_modes` lists the modes this domain may take — `labels` is offered for .ro domains only, never for ird's own infrastructure domains. Not charged (poll it freely while `nameservers_ready` is false).","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"mode":{"type":"string","enum":["shared","labels"]},"totp_code":{"type":"string"}},"required":["mode"],"additionalProperties":false}}}},"responses":{"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"202":{"description":"Zone republished under the new set; registry NS change enqueued (or listed in registry_error)","content":{"application/json":{"schema":{"type":"object","properties":{"origin":{"type":"string"},"mode":{"type":"string","enum":["shared","labels"]},"nameservers":{"type":"array","items":{"type":"string"}},"nameservers_ready":{"type":"boolean"},"available_modes":{"type":"array","items":{"type":"string","enum":["shared","labels"]}},"registry_action":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"registry_error":{"type":"string"}},"required":["origin","mode","nameservers","nameservers_ready","available_modes","registry_action"],"additionalProperties":false}}}},"200":{"description":"Already in the requested mode","content":{"application/json":{"schema":{"type":"object","properties":{"origin":{"type":"string"},"mode":{"type":"string","enum":["shared","labels"]},"nameservers":{"type":"array","items":{"type":"string"}},"nameservers_ready":{"type":"boolean"},"available_modes":{"type":"array","items":{"type":"string","enum":["shared","labels"]}},"registry_action":{"type":"null"}},"required":["origin","mode","nameservers","nameservers_ready","available_modes","registry_action"],"additionalProperties":false}}}},"503":{"description":"Private nameservers not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Registration or hosted zone not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, not a .ro domain, an ird infrastructure or platform zone, or a nameserver change is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"400":{"description":"Invalid mode","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Move the hosted zone to its private nameservers","description":"`mode: labels` moves the domain's hosted zone from ird's shared public nameservers onto its own private nameservers `<label>.nN.<ns domain>` (.ro domains only — 409 for others and for ird's infrastructure domains). Free: neither this request nor the registrar nameserver change is charged. The zone is republished under the new set (same records, no downtime) and a nameserver change is enqueued for you as `registry_action`; it waits until the private nameservers exist as host objects at the registry (created automatically, usually within minutes), so `nameservers_ready` may start false — poll the GET; should they never appear within the wait budget, the zone is put back on the shared nameservers and ird's operators are alerted (nothing to refund). `mode: shared` is the opt-out back to the shared set — the registrar change it enqueues is charged `domains.nameservers` as any nameserver change. The zone stays on every node it lives on across the switch. The current mode answers 200 with no registry action; 409 while a nameserver change is already open. Requires the registrant email to be verified and, on a sensitive domain, an authenticator code (`totp_code`).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/dns/dnssec":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"DNSSEC state","content":{"application/json":{"schema":{"type":"object","properties":{"dnssec":{"type":"object","properties":{"state":{"type":"string","enum":["pending-nodes","awaiting-ds","ds-published","removing-ds","unsigning-hold","disabled"]},"ds":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false},"not_before":{"type":"string"}},"required":["state"],"additionalProperties":false}},"required":["dnssec"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"DNSSEC state of the hosted zone","description":"The managed key's lifecycle stage and its DS tuple. States walk enable (pending-nodes → awaiting-ds → ds-published) and disable (removing-ds → unsigning-hold → disabled) in the safe order — the DS is only published after every nameserver serves the keys, and signing only stops after the DS has left parent caches.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"202":{"description":"DNSSEC enable started","content":{"application/json":{"schema":{"type":"object","properties":{"dnssec":{"type":"object","properties":{"state":{"type":"string","enum":["pending-nodes","awaiting-ds","ds-published","removing-ds","unsigning-hold","disabled"]},"ds":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false},"not_before":{"type":"string"}},"required":["state"],"additionalProperties":false}},"required":["dnssec"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"No hosted zone, or DNSSEC already enabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"DNS hosting not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Enable DNSSEC on the hosted zone","description":"One click: ird generates the keys, signs the zone on every nameserver, verifies each serves the keys, holds, and only then publishes the DS record at the registry (as a managed DS row). Charged per change; poll the state via GET.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"202":{"description":"DNSSEC disable started","content":{"application/json":{"schema":{"type":"object","properties":{"dnssec":{"type":"object","properties":{"state":{"type":"string","enum":["pending-nodes","awaiting-ds","ds-published","removing-ds","unsigning-hold","disabled"]},"ds":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false},"not_before":{"type":"string"}},"required":["state"],"additionalProperties":false}},"required":["dnssec"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Registration not found, or DNSSEC not enabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"A disable or an in-flight DS publish is already running","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"DNS hosting not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Disable DNSSEC on the hosted zone","description":"The safe order, server-side: the DS record is withdrawn from the registry first, then a hold covers the parent DS TTL, and only then does the zone stop signing — the domain stays resolvable throughout. Before the DS ever reached the registry the zone unsigns immediately. Charged per change.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/registrant":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"address1":{"type":"string"},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"type":"string"},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"type":"string"},"phone":{"type":"string"},"email":{"type":"string"},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"totp_code":{"type":"string"}},"required":["address1","city","country_code","phone","email","totp_code"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Missing or malformed contact fields, or email not verified for this account (error code email-unverified)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete profile / ownership verification required, or missing/invalid authenticator code (error codes totp-required / invalid-totp)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, no registrant contact on record yet, or a contact update is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Update the registrant's contact details","description":"Enqueue the registry's contact-update for this domain's registrant: address, city, phone, email and the other mutable contact fields. Free at the registry, no time lock, and the expiry date is NOT affected — this is the right way to keep a transferred-in domain's contact details current. The registry demands the full field set on every update, so send every required field even when unchanged. The protected identity fields (holder name, ID number, person type) cannot change here — that is the registrant change (trade) at POST /domains/registrations/{id}/trade, which resets the expiry. Two safeguards, because the registry sends codes and authorization keys to the registrant email: `email` must be your account email or an OTP-verified linked email (link one via POST /auth/emails — error code `email-unverified` otherwise), and `totp_code` must carry a fresh authenticator (or backup) code (`totp-required` / `invalid-totp` otherwise). Charged the `domains.contact-update` per-request price (0 at launch — see GET /credits/prices) up front, refunded on terminal failure; poll the returned action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/registrant-email/start":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Code sent","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["token","email_hint"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Already verified, or the registrant email is not readable (access denied at the registry)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"A code was already sent for this address — retry later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"The registrant snapshot is stale and could not be refreshed — try again shortly","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Start registrant-email ownership verification","description":"Sends a 6-digit code to the domain's registrant email on record (the address itself is never disclosed — the response carries only a masked hint). Verifying it is how a domain locked behind `ownership_verification_required` is unlocked: registrant details and every operation stay blocked until the email is confirmed to belong to this account. The registrant snapshot is refreshed from the registry first when stale; a failed refresh answers 503 rather than emailing a possibly-outdated address. Access-denied registrants (no readable email) answer 409 `registrant-email-unknown` — contact support.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/registrant-email/confirm":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string"},"code":{"type":"string"}},"required":["token","code"],"additionalProperties":false}}}},"responses":{"200":{"description":"Verified — the gate is open","content":{"application/json":{"schema":{"type":"object","properties":{"verified":{"type":"boolean"}},"required":["verified"],"additionalProperties":false}}}},"401":{"description":"Invalid or expired verification session","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The email belongs to another account — the domain has been attributed to it","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"Wrong code (attempts are limited)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Confirm the registrant-email code","description":"Checks the emailed code (5 attempts per session). Success links the address to your account and opens the ownership gate for **every** domain whose registrant carries it. When the address belongs to a different existing account it is never linked — the domain is attributed to that account instead and the request answers 409 `email-owned-by-another-account`.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/registrant-email/adopt":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"totp_code":{"type":"string"}},"required":["email","totp_code"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Email not verified for this account (error code email-unverified) or invalid","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete profile required, or missing/invalid authenticator code (error codes totp-required / invalid-totp)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not a transferred-in domain, the transfer-in is older than the adoption window, the email was already adopted once, snapshot unreadable, or a contact update already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Adopt the registrant contact email (transferred-in domains)","description":"The post-transfer choice: point a transferred-in domain's registrant contact email at an address this account controls. No verification of the previous holder's mailbox is required — the transfer's authorization key (obtained from the registrant) already proved consent. Requirements: the registration is active with a succeeded transfer-in by this account **within the last 30 days**, that adoption has not already been used once, the registrant snapshot is readable, `email` is your login or an OTP-verified linked email (link one via POST /auth/emails), and `totp_code` is a fresh authenticator (or backup) code — contact changes redirect where the registry sends codes and authorization keys, so they are step-up protected. The window and the one-shot rule exist because a transfer only proves who consented at the time: past that, use the verified registrant-email flow instead. Enqueues the standard free contact-update; once it lands, the ownership gate opens and the previous holder's key-recovery channel closes. The holder identity (name, person type) is untouched — becoming the holder is a trade.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/trade":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Trade quote","content":{"application/json":{"schema":{"type":"object","properties":{"discounted":{"type":"boolean"},"covered_years":{"type":"integer"},"max_years":{"type":"integer"},"current_expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"estimates":{"type":"array","items":{"type":"object","properties":{"years":{"type":"integer"},"price":{"type":"string"},"new_expires_at":{"type":"string"}},"required":["years","price","new_expires_at"],"additionalProperties":false}}},"required":["discounted","covered_years","max_years","current_expires_at","estimates"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Quote a registrant change (trade)","description":"Prices a ROTLD trade for this domain per period. IMPORTANT: a trade RESETS the expiry — the new expiry is the trade completion date plus the chosen `years`, remaining registration time is NOT carried over; each estimate includes the resulting `new_expires_at` so you can pick a period that covers what you would otherwise lose. `discounted` is true for transferred-in domains still under their previous (foreign) registrant: the first `covered_years` are included and further years bill at the swap rate. Charged per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"auth_key":{"type":"string"},"years":{"type":"integer","minimum":1,"maximum":10},"totp_code":{"type":"string"}},"required":["auth_key","years"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the registry action executes asynchronously; poll GET /domains/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"400":{"description":"Invalid years or missing auth key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not active, or a trade is already open","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Change a domain's registrant (trade)","description":"Enqueue a ROTLD registrant trade: your saved customer profile becomes the domain's registrant (the registry's paid trade procedure — a registrar transfer never changes the registrant). `auth_key` is the trade authorization key, which the CURRENT registrant obtains from the registry at rotld.ro/domadmin. IMPORTANT: the registry RESETS the expiry to the trade completion date plus `years` (capped at `registrar.max_years`); remaining registration time is NOT added — quote first (GET this path) and pick a period covering it. Charged up front per year (discounted swap pricing for transferred-in domains under a foreign registrant) and refunded on terminal failure. The registry confirms trades asynchronously — poll the returned action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/transfers-in":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"auth_key":{"type":"string"},"keep_nameservers":{"type":"boolean"},"use_ird_dns":{"type":"boolean"},"copy_dns":{"type":"boolean"},"then_trade":{"type":"boolean"}},"required":["domain","auth_key"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — awaiting the registry's transfer decision","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["registration","action"],"additionalProperties":false}}}},"400":{"description":"Invalid domain or missing key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Domain already has a live registration","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"copy_dns requested but the live DNS records could not be captured — nothing charged; retry or transfer without copy_dns","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Transfer a .ro domain to ird","description":"Enqueue an inbound transfer with the authorization key obtained from your current registrar/the registry. The flat transfer fee is charged up front and refunded if the transfer fails or is not approved in time (14 days); a transfer adds no renewal years — renew separately once the domain arrives. DNS: by default (`keep_nameservers`, true) the domain's live NS set is captured now and re-applied at the registry once the transfer lands, so nothing changes for visitors. Alternatively `use_ird_dns` hosts the zone on the ird nameservers when the transfer completes, and `copy_dns` (requires `use_ird_dns`) also copies the current live DNS records so the zone is reconstructed automatically — the record copy books the `domains.dns-snapshot` price on top. `then_trade` records that you also intend to become the holder: once the transfer lands you are emailed a link to finish the ownership change (a trade, priced separately per year — ROTLD keys are per-operation, so the trade key is supplied then, not now); a landed transfer is never rolled back if the trade doesn't follow.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/trades-in":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"auth_key":{"type":"string"},"years":{"type":"integer","minimum":1,"maximum":10},"keep_nameservers":{"type":"boolean"},"use_ird_dns":{"type":"boolean"},"copy_dns":{"type":"boolean"}},"required":["domain","auth_key","years"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — awaiting the registry's trade decision","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["registration","action"],"additionalProperties":false}}}},"400":{"description":"Invalid domain, years, or missing key","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Domain already has a live registration","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"copy_dns requested but the live DNS records could not be captured — nothing charged; retry or trade without copy_dns","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Trade a .ro domain into ird (become the holder)","description":"Enqueue an inbound trade: acquire a domain bought outside ird (person-to-person, a marketplace) — the domain may still sit at another registrar. `auth_key` is the trade authorization key the CURRENT registrant obtains in the registry's domain-administration panel and hands over to you; your saved customer profile becomes the new registrant. The registry RESETS the expiry to the trade completion date + `years` — remaining registration time is not added. Charged `years` × the full `domains.trade` per-year price up front (the swap discount applies only to domains already transferred in) and refunded if the trade terminally fails or is not completed in time. DNS options as on transfers: `keep_nameservers` (default) re-applies the current NS set once the trade lands, `use_ird_dns` hosts the zone on the ird nameservers instead, and `copy_dns` (requires `use_ird_dns`) also copies the current live records — the new holder may prefer a clean zone, so the copy is never implicit.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/adoptions":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"}},"required":["domain"],"additionalProperties":false}}}},"responses":{"201":{"description":"The adopted registration, active","content":{"application/json":{"schema":{"type":"object","properties":{"registration":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"tld":{"type":"string"},"state":{"type":"string","enum":["pending","reserved","active","pending-transfer-in","transferred-out","failed","closed"]},"period_years":{"type":"integer"},"registered_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"expired":{"type":"boolean"},"auto_renew":{"type":"boolean"},"sensitive":{"type":"boolean"},"nameservers":{"type":"array","items":{"type":"string"}},"hosts":{"type":"array","items":{"type":"object","properties":{"host":{"type":"string"},"ips":{"type":"array","items":{"type":"string"}}},"required":["host","ips"],"additionalProperties":false}},"dsdata":{"type":"array","items":{"type":"object","properties":{"keytag":{"type":"integer"},"alg":{"type":"integer"},"digest_type":{"type":"integer"},"digest":{"type":"string"}},"required":["keytag","alg","digest_type","digest"],"additionalProperties":false}},"transfer_out_requested_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"spent_total":{"type":"string"},"next_month_estimate":{"type":"string"},"transferred_in":{"type":"boolean"},"registrant":{"oneOf":[{"type":"object","properties":{"origin":{"type":"string","enum":["profile","registry"]},"access_denied":{"type":"boolean"},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"email":{"oneOf":[{"type":"string"},{"type":"null"}]},"phone":{"oneOf":[{"type":"string"},{"type":"null"}]},"fax":{"oneOf":[{"type":"string"},{"type":"null"}]},"address":{"oneOf":[{"type":"string"},{"type":"null"}]},"address1":{"oneOf":[{"type":"string"},{"type":"null"}]},"address2":{"oneOf":[{"type":"string"},{"type":"null"}]},"address3":{"oneOf":[{"type":"string"},{"type":"null"}]},"city":{"oneOf":[{"type":"string"},{"type":"null"}]},"state_province":{"oneOf":[{"type":"string"},{"type":"null"}]},"postal_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"country_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"person_type":{"oneOf":[{"type":"string"},{"type":"null"}]},"fetched_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["origin","access_denied","name","email","phone","fax","address","address1","address2","address3","city","state_province","postal_code","country_code","person_type","fetched_at"],"additionalProperties":false},{"type":"null"}]},"ownership_verification_required":{"type":"boolean"},"registrant_email_hint":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","domain","tld","state","period_years","registered_at","expires_at","expired","auto_renew","sensitive","nameservers","hosts","dsdata","transfer_out_requested_at","created_at"],"additionalProperties":false}},"required":["registration"],"additionalProperties":false}}}},"400":{"description":"Invalid domain","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Not ird-sponsored, registrant not yours, or a live registration exists","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"The registry could not be probed — adopt needs the probe; try again","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Adopt an ird-sponsored domain you already own","description":"Claim a domain that already sits under ird's registrar account with a registrant email you have proven control of (your login email, or an address verified through the registrant-email flow) but has no registration in any ird account. No registry operation runs — the registration is created directly as active from the registry's current facts. Use `GET /domains/preflight` to check whether a domain qualifies; if the registrant email is not yours, a trade-in is the right operation instead. Charged the `domains.adopt` contract (see `GET /credits/prices`).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/actions":{"get":{"parameters":[{"in":"query","name":"state","required":false,"schema":{"type":"string"}},{"in":"query","name":"cursor","required":false,"schema":{"type":"integer"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Actions","content":{"application/json":{"schema":{"type":"object","properties":{"actions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"next_cursor":{"oneOf":[{"type":"integer"},{"type":"null"}]}},"required":["actions","next_cursor"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"List your registry actions","description":"Every registrar operation you've enqueued, newest first; filter with `state`, paginate with `cursor` (the last `seq` served). Charged per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/actions/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Action","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Poll a registry action","description":"Terminal states: succeeded, failed (charge refunded), cancelled. submitted/awaiting-registry/reconciling mean the registry is being consulted — keep polling. Charged per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/actions/{id}/cancel":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Cancelled + refunded","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"seq":{"type":"integer"},"type":{"type":"string","enum":["register","activate","renew","transfer-in","transfer-out","reset-ns","trade","trade-in","host-create","host-update","host-delete","dsdata-add","dsdata-remove","contact-update","sync-info","sync-contact"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","awaiting-registry","reconciling","succeeded","failed","cancelled"]},"registration_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"charged":{"oneOf":[{"type":"string"},{"type":"null"}]},"refunded":{"type":"boolean"},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_code":{"oneOf":[{"type":"string"},{"type":"null"}]},"error_hint":{"oneOf":[{"type":"string","enum":["transfer-prohibited","invalid-auth-key","domain-not-found","other-registrar"]},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"submitted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","seq","type","state","registration_id","charged","refunded","error","error_code","error_hint","result","created_at","submitted_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Action already progressed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["registrations"],"summary":"Cancel a queued action","description":"Only while the action has not touched the registry (queued); the up-front charge is refunded immediately.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/domains/registrations/{id}/grants":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Grants","content":{"application/json":{"schema":{"type":"object","properties":{"grants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"registration_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"state":{"type":"string","enum":["pending","active","revoked","declined","left"]},"invited_email":{"type":"string"},"payer":{"description":"Who is billed for usage under the grant — the domain owner (the default), the grantee, or split (each charge booked half to each). Fixed at invite time; resources a delegate creates live on the owner's account in every mode, and IPFS gateway egress bills the owner regardless.","type":"string","enum":["owner","grantee","split"]},"inactive":{"description":"True on a pending/active grant whose registration expired, transferred out or changed owner — it confers nothing until re-granted.","type":"boolean"},"created_at":{"type":"string"},"accepted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string"},"owner_email":{"type":"string"}},"required":["id","registration_id","scopes","state","invited_email","payer","inactive","created_at","accepted_at","revoked_at"],"additionalProperties":false}}},"required":["grants"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["sharing"],"summary":"Who has delegated access to this domain","description":"Every grant ever minted on the registration, newest first — pending invites, active grants and ended history. Rows whose validity lapsed (the registration expired, transferred out or changed owner) carry `inactive: true`. Session JWT only.","security":[{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"payer":{"type":"string","enum":["owner","grantee","split"]},"totp_code":{"type":"string"}},"required":["email","scopes"],"additionalProperties":false}}}},"responses":{"201":{"description":"Pending grant","content":{"application/json":{"schema":{"type":"object","properties":{"grant":{"type":"object","properties":{"id":{"type":"string"},"registration_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"state":{"type":"string","enum":["pending","active","revoked","declined","left"]},"invited_email":{"type":"string"},"payer":{"description":"Who is billed for usage under the grant — the domain owner (the default), the grantee, or split (each charge booked half to each). Fixed at invite time; resources a delegate creates live on the owner's account in every mode, and IPFS gateway egress bills the owner regardless.","type":"string","enum":["owner","grantee","split"]},"inactive":{"description":"True on a pending/active grant whose registration expired, transferred out or changed owner — it confers nothing until re-granted.","type":"boolean"},"created_at":{"type":"string"},"accepted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string"},"owner_email":{"type":"string"}},"required":["id","registration_id","scopes","state","invited_email","payer","inactive","created_at","accepted_at","revoked_at"],"additionalProperties":false}},"required":["grant"],"additionalProperties":false}}}},"400":{"description":"Invalid scopes/email, or no ird account with that email (error code email-unknown)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Missing/invalid authenticator code (error codes totp-required / invalid-totp), or the action is otherwise refused (ownership-verification-required)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"An invite for that email is already pending, or the account already has access","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["sharing"],"summary":"Invite another customer to manage parts of this domain","description":"Grants `email` (an existing ird account) the listed scopes on this domain — `dns` (hosted-zone records), `tunnel` (tunnels on and under it), `ipfs` (gateway-domain bindings), `vps` (servers anchored to it or a subdomain at create) — pending until they accept. `payer` picks who is billed for their work: `owner` (the default — every charge lands on YOUR credits), `grantee` (per-request and hourly charges bill their account), or `split` (every charge books as two halves, one on each account; hourly subscriptions bill half-and-half each hour). IPFS gateway egress still bills yours in every mode, and resources they create belong to your account. The choice is fixed for the grant's lifetime — to change scopes or payer, revoke and re-invite. Registrar rights (renew, transfer, nameservers, …) are never delegable. Session JWT only, and every invite demands a fresh authenticator (or backup) code in `totp_code`.","security":[{"accountJwt":[]}]}},"/domains/registrations/{id}/grants/{grant-id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"grant-id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Revoked grant","content":{"application/json":{"schema":{"type":"object","properties":{"grant":{"type":"object","properties":{"id":{"type":"string"},"registration_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"state":{"type":"string","enum":["pending","active","revoked","declined","left"]},"invited_email":{"type":"string"},"payer":{"description":"Who is billed for usage under the grant — the domain owner (the default), the grantee, or split (each charge booked half to each). Fixed at invite time; resources a delegate creates live on the owner's account in every mode, and IPFS gateway egress bills the owner regardless.","type":"string","enum":["owner","grantee","split"]},"inactive":{"description":"True on a pending/active grant whose registration expired, transferred out or changed owner — it confers nothing until re-granted.","type":"boolean"},"created_at":{"type":"string"},"accepted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string"},"owner_email":{"type":"string"}},"required":["id","registration_id","scopes","state","invited_email","payer","inactive","created_at","accepted_at","revoked_at"],"additionalProperties":false}},"required":["grant"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["sharing"],"summary":"Revoke delegated access","description":"Ends a pending or active grant immediately. Deliberately free of the authenticator gate — removing access must never be harder than keeping it. Session JWT only.","security":[{"accountJwt":[]}]}},"/dns/domains":{"get":{"responses":{"200":{"description":"Hosted domains","content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"object","properties":{"origin":{"type":"string"},"nodes":{"type":"array","items":{"type":"string"}},"default_ttl":{"type":"integer"},"delegated":{"description":"Present (true) on a domain another account shared with this one through a dns grant: records are editable, changes are billed per the share's payer setting (the owner by default).","type":"boolean"}},"required":["origin","nodes","default_ttl"],"additionalProperties":false}}},"required":["domains"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Your hosted DNS domains","description":"The domains whose DNS is hosted on ird nameservers, each with the nodes serving it. Requires an API key or account JWT.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/dns/domains/{domain}":{"get":{"parameters":[{"in":"path","name":"domain","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Zone with records","content":{"application/json":{"schema":{"type":"object","properties":{"origin":{"type":"string"},"nameservers":{"type":"array","items":{"type":"string"}},"nameservers_mode":{"type":"string","enum":["shared","labels"]},"nodes":{"type":"array","items":{"type":"string"}},"default_ttl":{"type":"integer"},"records":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"ttl":{"oneOf":[{"type":"integer"},{"type":"null"}]},"data":{"type":"object","additionalProperties":{}},"managed_by":{"type":"string","enum":["tunnel","app","vps","platform"]},"tunnel_id":{"type":"string"},"deployment_id":{"type":"string"},"connection_id":{"type":"string"},"instance_id":{"type":"string"},"purpose":{"type":"string"}},"required":["name","type","class","ttl","data"],"additionalProperties":false}}},"required":["origin","nameservers","nameservers_mode","nodes","default_ttl","records"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"A hosted domain's zone","description":"The domain's logical zone: published nameservers, the nodes serving it, and every record. Only your own zones are visible. A record maintained by one of your tunnels carries `managed_by: \"tunnel\"` and its `tunnel_id` — it is read-only while the tunnel lives (mutations answer 409) and is removed when the tunnel is deleted.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/dns/domains/{domain}/records":{"put":{"parameters":[{"in":"path","name":"domain","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"record":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"ttl":{"oneOf":[{"type":"integer"},{"type":"null"}]},"data":{"type":"object","additionalProperties":{}}},"required":["name","type","class","ttl","data"],"additionalProperties":false},"records":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"ttl":{"oneOf":[{"type":"integer"},{"type":"null"}]},"data":{"type":"object","additionalProperties":{}}},"required":["name","type","class","ttl","data"],"additionalProperties":false}},"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"RRset stored","content":{"application/json":{"schema":{"type":"object","properties":{"records":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"ttl":{"oneOf":[{"type":"integer"},{"type":"null"}]},"data":{"type":"object","additionalProperties":{}}},"required":["name","type","class","ttl","data"],"additionalProperties":false}},"record":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"ttl":{"oneOf":[{"type":"integer"},{"type":"null"}]},"data":{"type":"object","additionalProperties":{}}},"required":["name","type","class","ttl","data"],"additionalProperties":false}},"required":["records","record"],"additionalProperties":false}}}},"400":{"description":"Invalid record","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The RRset is managed by your tunnel — delete the tunnel to change it","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"DNS hosting not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Set a DNS record or RRset","description":"Replaces the RRset at (name, type, class) across every node copy of the zone in a single signed change — DNS updates a whole RRset, never one value inside it. Send `record` for a single value, or `records` for a multi-value RRset (two MX, round-robin A); every entry of `records` must share name, type and class. `data` is the record's typed payload: A/AAAA `{\"address\": ...}`, CNAME/NS `{\"name\": ...}`, MX `{\"preference\": ..., \"exchange\": ...}`, TXT `{\"texts\": [...]}`, SRV `{\"priority\",\"weight\",\"port\",\"target\"}`, CAA `{\"flags\",\"tag\",\"value\"}`. In hostname-valued data fields (CNAME/NS/PTR `name`, MX `exchange`, SRV `target`), `@` is shorthand for the zone origin — stored expanded to the full name. TTL defaults to the zone's default. The apex NS set is managed by ird and cannot be set here.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"domain","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string"},"class":{"type":"string"},"totp_code":{"type":"string"}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"Record deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false}}}},"400":{"description":"Missing record name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile required, or the domain's registrant email is not verified for this account (error code ownership-verification-required) — verify it first via the registrant-email flow. Domains marked sensitive additionally demand a fresh authenticator (or backup) code in `totp_code` on every change (error codes totp-required / invalid-totp) and refuse API-key callers outright (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The record is managed by your tunnel — delete the tunnel to change it","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"DNS hosting not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Delete a DNS record","description":"Deletes the record(s) matching `name` (narrowed by `type` and `class` when given) across every node copy of the zone in a single signed change.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/dns/claims":{"get":{"parameters":[{"in":"query","name":"state","required":false,"schema":{"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"Rows to return, 1..500 (default 50)."}],"responses":{"200":{"description":"Your claims","content":{"application/json":{"schema":{"type":"object","properties":{"claims":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"domain":{"description":"The domain in DNS (punycode) form.","type":"string"},"domain_unicode":{"description":"The domain in display (Unicode) form — equal to `domain` unless it is an IDN.","type":"string"},"state":{"type":"string","enum":["pending","verified","active","lapsed","revoked","expired"]},"expires_at":{"description":"While pending: when the claim's window closes — the parent zone must delegate the domain to the claim's nameservers before it, or the claim lapses. Null once verified.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers to set for the domain at its registrar (per-claim private names on ird's nameserver domain) — given from the start, and the claim's proof: it activates once the parent zone lists exactly these.","type":"array","items":{"type":"string"}},"delegation":{"type":"object","properties":{"ok":{"type":"boolean"},"partial":{"type":"boolean"},"names":{"type":"array","items":{"type":"string"}},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"deadline_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"lost_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ds_present":{"type":"boolean"}},"required":["ok","partial","names","checked_at","deadline_at","lost_at","ds_present"],"additionalProperties":false},"registry":{"type":"object","properties":{"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["expires_at","status","checked_at"],"additionalProperties":false},"sensitive":{"type":"boolean"},"seed_snapshot_id":{"description":"The attached copy of the domain's current records (see `PUT /dns/claims/{id}/seed`), or null — the zone then starts empty.","oneOf":[{"type":"string"},{"type":"null"}]},"seed":{"description":"The attached copy in full (single-claim responses only).","oneOf":[{"type":"object","properties":{"snapshot_id":{"description":"The `GET /domains/dns-snapshot` copy the zone is seeded from at activation.","type":"string"},"taken_at":{"description":"When the copy was read from the domain's previous nameservers.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers the copy was read from.","type":"array","items":{"type":"string"}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"record_count":{"type":"integer"},"records":{"description":"The records exactly as they will seed the zone (the apex SOA/NS of the old host dropped — ird synthesizes its own).","type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["snapshot_id","taken_at","nameservers","record_count","records"],"additionalProperties":false},{"type":"null"}]},"last_check":{"description":"The last delegation read while pending — the customer's verify or the monitor's free recheck every few minutes — in the verify `check` shape; null before the first read or once a health check replaced it.","oneOf":[{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false},{"type":"null"}]},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"activated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ended_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"end_reason":{"oneOf":[{"type":"string","enum":["released","superseded","registered","admin","not-verified","not-delegated","delegation-lost","grace-expired","registry-gone"]},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","domain","domain_unicode","state","expires_at","nameservers","delegation","registry","sensitive","seed_snapshot_id","last_check","verified_at","activated_at","ended_at","end_reason","created_at"],"additionalProperties":false}}},"required":["claims"],"additionalProperties":false}}}},"400":{"description":"Unknown state filter, or limit outside 1..500","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Your bring-your-own domain claims","description":"Domains you hold at another registrar and host (or are about to host) on ird DNS: every live claim plus the ones that ended in the last 30 days, newest first. `state` narrows to one of pending / verified / active / lapsed / revoked / expired; `limit` caps the rows returned (1..500, default 50). Requires an API key or account JWT and a complete customer profile. Charged `dns.manage` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"}},"required":["domain"],"additionalProperties":false}}}},"responses":{"201":{"description":"Claim opened; set the nameservers at the registrar","content":{"application/json":{"schema":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"string"},"domain":{"description":"The domain in DNS (punycode) form.","type":"string"},"domain_unicode":{"description":"The domain in display (Unicode) form — equal to `domain` unless it is an IDN.","type":"string"},"state":{"type":"string","enum":["pending","verified","active","lapsed","revoked","expired"]},"expires_at":{"description":"While pending: when the claim's window closes — the parent zone must delegate the domain to the claim's nameservers before it, or the claim lapses. Null once verified.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers to set for the domain at its registrar (per-claim private names on ird's nameserver domain) — given from the start, and the claim's proof: it activates once the parent zone lists exactly these.","type":"array","items":{"type":"string"}},"delegation":{"type":"object","properties":{"ok":{"type":"boolean"},"partial":{"type":"boolean"},"names":{"type":"array","items":{"type":"string"}},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"deadline_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"lost_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ds_present":{"type":"boolean"}},"required":["ok","partial","names","checked_at","deadline_at","lost_at","ds_present"],"additionalProperties":false},"registry":{"type":"object","properties":{"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["expires_at","status","checked_at"],"additionalProperties":false},"sensitive":{"type":"boolean"},"seed_snapshot_id":{"description":"The attached copy of the domain's current records (see `PUT /dns/claims/{id}/seed`), or null — the zone then starts empty.","oneOf":[{"type":"string"},{"type":"null"}]},"seed":{"description":"The attached copy in full (single-claim responses only).","oneOf":[{"type":"object","properties":{"snapshot_id":{"description":"The `GET /domains/dns-snapshot` copy the zone is seeded from at activation.","type":"string"},"taken_at":{"description":"When the copy was read from the domain's previous nameservers.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers the copy was read from.","type":"array","items":{"type":"string"}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"record_count":{"type":"integer"},"records":{"description":"The records exactly as they will seed the zone (the apex SOA/NS of the old host dropped — ird synthesizes its own).","type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["snapshot_id","taken_at","nameservers","record_count","records"],"additionalProperties":false},{"type":"null"}]},"last_check":{"description":"The last delegation read while pending — the customer's verify or the monitor's free recheck every few minutes — in the verify `check` shape; null before the first read or once a health check replaced it.","oneOf":[{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false},{"type":"null"}]},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"activated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ended_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"end_reason":{"oneOf":[{"type":"string","enum":["released","superseded","registered","admin","not-verified","not-delegated","delegation-lost","grace-expired","registry-gone"]},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","domain","domain_unicode","state","expires_at","nameservers","delegation","registry","sensitive","seed_snapshot_id","last_check","verified_at","activated_at","ended_at","end_reason","created_at"],"additionalProperties":false}},"required":["claim"],"additionalProperties":false}}}},"400":{"description":"Not a registrable domain, a .ro domain (transfer it in instead), an ird infrastructure name, or a per-account cap (claimed domains, claims per day) reached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Already managed at ird (registered here or hosted by an operator), assigned to the platform, or already held by you","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Private nameservers not configured on this deployment (no label secret, or no nameserver node labelled yet)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Claim a domain you hold elsewhere","description":"Opens a claim on a registrable domain (`example.com`, not a subdomain) registered at another registrar so ird can be its DNS. The response carries the `nameservers` to set for the domain at your registrar — private names on ird's nameserver domain, unique to this claim. Nothing is hosted yet: ird reads the domain's delegation at its parent zone (every few minutes, or on demand through verify), and the moment the parent lists exactly those nameservers the claim activates and a zone is created for the domain — seeded from the copy of its current records you attached while pending (`GET /domains/dns-snapshot` **before** switching the nameservers, then `PUT /dns/claims/{id}/seed`), or **empty** without one, in which case the domain does not resolve until you add its records (`PUT /dns/domains/{domain}/records`). If the domain carries a DS record at its parent, remove it at the registrar before switching — claimed zones are unsigned. The window to switch is `expires_at` (7 days); past it the claim lapses and a new one is opened. ird does not register, renew or transfer the domain: expiry stays your business. `.ro` domains cannot be claimed — ird is their registrar, transfer them in instead (400). Domains already managed at ird (registered here, or hosted by an operator) cannot be claimed (409). Idempotent on your own pending claim for the same domain; a claim past its window is replaced by a fresh one. Requires a complete customer profile. Charged `dns.manage` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/dns/claims/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The claim","content":{"application/json":{"schema":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"string"},"domain":{"description":"The domain in DNS (punycode) form.","type":"string"},"domain_unicode":{"description":"The domain in display (Unicode) form — equal to `domain` unless it is an IDN.","type":"string"},"state":{"type":"string","enum":["pending","verified","active","lapsed","revoked","expired"]},"expires_at":{"description":"While pending: when the claim's window closes — the parent zone must delegate the domain to the claim's nameservers before it, or the claim lapses. Null once verified.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers to set for the domain at its registrar (per-claim private names on ird's nameserver domain) — given from the start, and the claim's proof: it activates once the parent zone lists exactly these.","type":"array","items":{"type":"string"}},"delegation":{"type":"object","properties":{"ok":{"type":"boolean"},"partial":{"type":"boolean"},"names":{"type":"array","items":{"type":"string"}},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"deadline_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"lost_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ds_present":{"type":"boolean"}},"required":["ok","partial","names","checked_at","deadline_at","lost_at","ds_present"],"additionalProperties":false},"registry":{"type":"object","properties":{"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["expires_at","status","checked_at"],"additionalProperties":false},"sensitive":{"type":"boolean"},"seed_snapshot_id":{"description":"The attached copy of the domain's current records (see `PUT /dns/claims/{id}/seed`), or null — the zone then starts empty.","oneOf":[{"type":"string"},{"type":"null"}]},"seed":{"description":"The attached copy in full (single-claim responses only).","oneOf":[{"type":"object","properties":{"snapshot_id":{"description":"The `GET /domains/dns-snapshot` copy the zone is seeded from at activation.","type":"string"},"taken_at":{"description":"When the copy was read from the domain's previous nameservers.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers the copy was read from.","type":"array","items":{"type":"string"}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"record_count":{"type":"integer"},"records":{"description":"The records exactly as they will seed the zone (the apex SOA/NS of the old host dropped — ird synthesizes its own).","type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["snapshot_id","taken_at","nameservers","record_count","records"],"additionalProperties":false},{"type":"null"}]},"last_check":{"description":"The last delegation read while pending — the customer's verify or the monitor's free recheck every few minutes — in the verify `check` shape; null before the first read or once a health check replaced it.","oneOf":[{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false},{"type":"null"}]},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"activated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ended_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"end_reason":{"oneOf":[{"type":"string","enum":["released","superseded","registered","admin","not-verified","not-delegated","delegation-lost","grace-expired","registry-gone"]},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","domain","domain_unicode","state","expires_at","nameservers","delegation","registry","sensitive","seed_snapshot_id","last_check","verified_at","activated_at","ended_at","end_reason","created_at"],"additionalProperties":false}},"required":["claim"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"A claim","description":"One of your claims with the nameservers to set at the registrar, its window (while pending), the latest delegation read and registry facts. Another account's claim answers 404. Charged `dns.manage` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The ended claim","content":{"application/json":{"schema":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"string"},"domain":{"description":"The domain in DNS (punycode) form.","type":"string"},"domain_unicode":{"description":"The domain in display (Unicode) form — equal to `domain` unless it is an IDN.","type":"string"},"state":{"type":"string","enum":["pending","verified","active","lapsed","revoked","expired"]},"expires_at":{"description":"While pending: when the claim's window closes — the parent zone must delegate the domain to the claim's nameservers before it, or the claim lapses. Null once verified.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers to set for the domain at its registrar (per-claim private names on ird's nameserver domain) — given from the start, and the claim's proof: it activates once the parent zone lists exactly these.","type":"array","items":{"type":"string"}},"delegation":{"type":"object","properties":{"ok":{"type":"boolean"},"partial":{"type":"boolean"},"names":{"type":"array","items":{"type":"string"}},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"deadline_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"lost_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ds_present":{"type":"boolean"}},"required":["ok","partial","names","checked_at","deadline_at","lost_at","ds_present"],"additionalProperties":false},"registry":{"type":"object","properties":{"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["expires_at","status","checked_at"],"additionalProperties":false},"sensitive":{"type":"boolean"},"seed_snapshot_id":{"description":"The attached copy of the domain's current records (see `PUT /dns/claims/{id}/seed`), or null — the zone then starts empty.","oneOf":[{"type":"string"},{"type":"null"}]},"seed":{"description":"The attached copy in full (single-claim responses only).","oneOf":[{"type":"object","properties":{"snapshot_id":{"description":"The `GET /domains/dns-snapshot` copy the zone is seeded from at activation.","type":"string"},"taken_at":{"description":"When the copy was read from the domain's previous nameservers.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers the copy was read from.","type":"array","items":{"type":"string"}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"record_count":{"type":"integer"},"records":{"description":"The records exactly as they will seed the zone (the apex SOA/NS of the old host dropped — ird synthesizes its own).","type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["snapshot_id","taken_at","nameservers","record_count","records"],"additionalProperties":false},{"type":"null"}]},"last_check":{"description":"The last delegation read while pending — the customer's verify or the monitor's free recheck every few minutes — in the verify `check` shape; null before the first read or once a health check replaced it.","oneOf":[{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false},{"type":"null"}]},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"activated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ended_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"end_reason":{"oneOf":[{"type":"string","enum":["released","superseded","registered","admin","not-verified","not-delegated","delegation-lost","grace-expired","registry-gone"]},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","domain","domain_unicode","state","expires_at","nameservers","delegation","registry","sensitive","seed_snapshot_id","last_check","verified_at","activated_at","ended_at","end_reason","created_at"],"additionalProperties":false}},"required":["claim"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The claim has already ended","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Release a claim","description":"Ends the claim (state `revoked`, reason `released`) and takes the hosted zone out of service — a snapshot of its records is kept. Point the domain's nameservers elsewhere first or it goes dark. Free.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/dns/claims/{id}/verify":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Check result and the claim as it stands","content":{"application/json":{"schema":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"string"},"domain":{"description":"The domain in DNS (punycode) form.","type":"string"},"domain_unicode":{"description":"The domain in display (Unicode) form — equal to `domain` unless it is an IDN.","type":"string"},"state":{"type":"string","enum":["pending","verified","active","lapsed","revoked","expired"]},"expires_at":{"description":"While pending: when the claim's window closes — the parent zone must delegate the domain to the claim's nameservers before it, or the claim lapses. Null once verified.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers to set for the domain at its registrar (per-claim private names on ird's nameserver domain) — given from the start, and the claim's proof: it activates once the parent zone lists exactly these.","type":"array","items":{"type":"string"}},"delegation":{"type":"object","properties":{"ok":{"type":"boolean"},"partial":{"type":"boolean"},"names":{"type":"array","items":{"type":"string"}},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"deadline_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"lost_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ds_present":{"type":"boolean"}},"required":["ok","partial","names","checked_at","deadline_at","lost_at","ds_present"],"additionalProperties":false},"registry":{"type":"object","properties":{"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["expires_at","status","checked_at"],"additionalProperties":false},"sensitive":{"type":"boolean"},"seed_snapshot_id":{"description":"The attached copy of the domain's current records (see `PUT /dns/claims/{id}/seed`), or null — the zone then starts empty.","oneOf":[{"type":"string"},{"type":"null"}]},"seed":{"description":"The attached copy in full (single-claim responses only).","oneOf":[{"type":"object","properties":{"snapshot_id":{"description":"The `GET /domains/dns-snapshot` copy the zone is seeded from at activation.","type":"string"},"taken_at":{"description":"When the copy was read from the domain's previous nameservers.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers the copy was read from.","type":"array","items":{"type":"string"}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"record_count":{"type":"integer"},"records":{"description":"The records exactly as they will seed the zone (the apex SOA/NS of the old host dropped — ird synthesizes its own).","type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["snapshot_id","taken_at","nameservers","record_count","records"],"additionalProperties":false},{"type":"null"}]},"last_check":{"description":"The last delegation read while pending — the customer's verify or the monitor's free recheck every few minutes — in the verify `check` shape; null before the first read or once a health check replaced it.","oneOf":[{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false},{"type":"null"}]},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"activated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ended_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"end_reason":{"oneOf":[{"type":"string","enum":["released","superseded","registered","admin","not-verified","not-delegated","delegation-lost","grace-expired","registry-gone"]},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","domain","domain_unicode","state","expires_at","nameservers","delegation","registry","sensitive","seed_snapshot_id","last_check","verified_at","activated_at","ended_at","end_reason","created_at"],"additionalProperties":false},"check":{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false}},"required":["claim","check"],"additionalProperties":false}}}},"400":{"description":"Cap lowered below your live claims since the claim was opened, or the zone service refused the provisioning input","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The claim is no longer pending, another claim holds the domain, or its zone is already hosted on ird DNS for another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Checked again within a minute, or the hourly per-account verify cap is reached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Private nameservers, DNS hosting or DNS nodes not configured on this deployment, a nameserver node named by the claim no longer enrolled, the zone could not be provisioned, or the hourly verify counter is unreachable (verification is temporarily unavailable)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Check a claim's nameservers now","description":"Reads the domain's delegation at its parent zone now — the parent zone's own servers are asked for a non-recursive referral, never a resolver — and compares it with the claim's `nameservers`. When the parent lists exactly those names the claim is proven: the zone is provisioned on ird DNS (state `active`) — seeded from the attached copy of the records (`seed`), or **empty** apart from its apex, in which case add the records right away: the domain does not resolve until then. Anything else is not an error: the response is 200 with `check.ok` false, a `reason` (`not-delegated` — the parent lists no nameservers for the domain, `parent-unreachable` — retry later, `partial` — only some of the claim's nameservers are set, `delegated-to-ird` — the domain points at ird nameservers that are not this claim's (another account's, or the shared set), `elsewhere` — a third party's nameservers, `expired`, `activation-refused` — the parent points at ird but the zone could not be provisioned; ird has been alerted), the `names` the parent lists and the claim's names still `missing`. A claim past its window (7 days) ends as lapsed; open a new one. One verify per claim per minute and a per-account hourly cap (429 beyond) — ird also reads every pending claim on its own every few minutes; when the cap counter is unreachable the verify answers 503 rather than running uncounted. Charged `dns.manage` per request — a failed check is charged too.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/dns/claims/{id}/seed":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"snapshot_id":{"type":"string"}},"required":["snapshot_id"],"additionalProperties":false}}}},"responses":{"200":{"description":"The claim with its seed","content":{"application/json":{"schema":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"string"},"domain":{"description":"The domain in DNS (punycode) form.","type":"string"},"domain_unicode":{"description":"The domain in display (Unicode) form — equal to `domain` unless it is an IDN.","type":"string"},"state":{"type":"string","enum":["pending","verified","active","lapsed","revoked","expired"]},"expires_at":{"description":"While pending: when the claim's window closes — the parent zone must delegate the domain to the claim's nameservers before it, or the claim lapses. Null once verified.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers to set for the domain at its registrar (per-claim private names on ird's nameserver domain) — given from the start, and the claim's proof: it activates once the parent zone lists exactly these.","type":"array","items":{"type":"string"}},"delegation":{"type":"object","properties":{"ok":{"type":"boolean"},"partial":{"type":"boolean"},"names":{"type":"array","items":{"type":"string"}},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"deadline_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"lost_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ds_present":{"type":"boolean"}},"required":["ok","partial","names","checked_at","deadline_at","lost_at","ds_present"],"additionalProperties":false},"registry":{"type":"object","properties":{"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["expires_at","status","checked_at"],"additionalProperties":false},"sensitive":{"type":"boolean"},"seed_snapshot_id":{"description":"The attached copy of the domain's current records (see `PUT /dns/claims/{id}/seed`), or null — the zone then starts empty.","oneOf":[{"type":"string"},{"type":"null"}]},"seed":{"description":"The attached copy in full (single-claim responses only).","oneOf":[{"type":"object","properties":{"snapshot_id":{"description":"The `GET /domains/dns-snapshot` copy the zone is seeded from at activation.","type":"string"},"taken_at":{"description":"When the copy was read from the domain's previous nameservers.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers the copy was read from.","type":"array","items":{"type":"string"}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"record_count":{"type":"integer"},"records":{"description":"The records exactly as they will seed the zone (the apex SOA/NS of the old host dropped — ird synthesizes its own).","type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["snapshot_id","taken_at","nameservers","record_count","records"],"additionalProperties":false},{"type":"null"}]},"last_check":{"description":"The last delegation read while pending — the customer's verify or the monitor's free recheck every few minutes — in the verify `check` shape; null before the first read or once a health check replaced it.","oneOf":[{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false},{"type":"null"}]},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"activated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ended_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"end_reason":{"oneOf":[{"type":"string","enum":["released","superseded","registered","admin","not-verified","not-delegated","delegation-lost","grace-expired","registry-gone"]},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","domain","domain_unicode","state","expires_at","nameservers","delegation","registry","sensitive","seed_snapshot_id","last_check","verified_at","activated_at","ended_at","end_reason","created_at"],"additionalProperties":false}},"required":["claim"],"additionalProperties":false}}}},"400":{"description":"The copy holds no records, was read from ird's nameservers (taken after the switch), is an NS-only or failed capture, or exceeds the claimed-zone record cap","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Not your claim, or not your snapshot of this domain","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The claim is no longer pending","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Attach a copy of the domain's current records to a pending claim","description":"Copy the domain's current DNS into the zone ird creates at activation, instead of starting empty: take the copy with `GET /domains/dns-snapshot?domain=` **while the domain still resolves at its previous host** (before switching the nameservers — afterwards the copy would be read from ird's own servers and is refused), then attach its `id` here. The response's `seed.records` are exactly what will seed the zone (the old apex SOA/NS are dropped, ird publishes its own); records the nodes cannot serve are skipped at activation. A later attach replaces the seed — re-take the copy with extra `names=` to pick up subdomains the common sweep missed. Only your own snapshot of this domain is accepted (404 otherwise). Charged `dns.manage` per request; the copy itself is charged `domains.dns-snapshot`.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The claim without a seed","content":{"application/json":{"schema":{"type":"object","properties":{"claim":{"type":"object","properties":{"id":{"type":"string"},"domain":{"description":"The domain in DNS (punycode) form.","type":"string"},"domain_unicode":{"description":"The domain in display (Unicode) form — equal to `domain` unless it is an IDN.","type":"string"},"state":{"type":"string","enum":["pending","verified","active","lapsed","revoked","expired"]},"expires_at":{"description":"While pending: when the claim's window closes — the parent zone must delegate the domain to the claim's nameservers before it, or the claim lapses. Null once verified.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers to set for the domain at its registrar (per-claim private names on ird's nameserver domain) — given from the start, and the claim's proof: it activates once the parent zone lists exactly these.","type":"array","items":{"type":"string"}},"delegation":{"type":"object","properties":{"ok":{"type":"boolean"},"partial":{"type":"boolean"},"names":{"type":"array","items":{"type":"string"}},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"deadline_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"lost_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ds_present":{"type":"boolean"}},"required":["ok","partial","names","checked_at","deadline_at","lost_at","ds_present"],"additionalProperties":false},"registry":{"type":"object","properties":{"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"checked_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["expires_at","status","checked_at"],"additionalProperties":false},"sensitive":{"type":"boolean"},"seed_snapshot_id":{"description":"The attached copy of the domain's current records (see `PUT /dns/claims/{id}/seed`), or null — the zone then starts empty.","oneOf":[{"type":"string"},{"type":"null"}]},"seed":{"description":"The attached copy in full (single-claim responses only).","oneOf":[{"type":"object","properties":{"snapshot_id":{"description":"The `GET /domains/dns-snapshot` copy the zone is seeded from at activation.","type":"string"},"taken_at":{"description":"When the copy was read from the domain's previous nameservers.","oneOf":[{"type":"string"},{"type":"null"}]},"nameservers":{"description":"The nameservers the copy was read from.","type":"array","items":{"type":"string"}},"meta":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"record_count":{"type":"integer"},"records":{"description":"The records exactly as they will seed the zone (the apex SOA/NS of the old host dropped — ird synthesizes its own).","type":"array","items":{"type":"object","additionalProperties":{}}}},"required":["snapshot_id","taken_at","nameservers","record_count","records"],"additionalProperties":false},{"type":"null"}]},"last_check":{"description":"The last delegation read while pending — the customer's verify or the monitor's free recheck every few minutes — in the verify `check` shape; null before the first read or once a health check replaced it.","oneOf":[{"type":"object","properties":{"ok":{"description":"True when the parent zone delegates the domain to exactly the claim's nameservers.","type":"boolean"},"reason":{"oneOf":[{"type":"string","enum":["parent-unreachable","not-delegated","partial","delegated-to-ird","elsewhere","expired","activation-refused"]},{"type":"null"}]},"names":{"description":"The nameservers the parent zone lists for the domain (lower-case, no trailing dot).","type":"array","items":{"type":"string"}},"nameserver_count":{"description":"How many nameservers the parent lists.","type":"integer"},"missing":{"description":"The claim's nameservers the parent does not list yet — what is still to set at the registrar.","type":"array","items":{"type":"string"}},"ds_present":{"description":"A DS record sits at the parent. Claimed zones are unsigned: remove it at the registrar or validating resolvers refuse the domain.","type":"boolean"},"message":{"description":"With reason `activation-refused`: why the service could not provision the zone although the parent already delegates to ird.","type":"string"},"error":{"type":"string"}},"required":["ok"],"additionalProperties":false},{"type":"null"}]},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"activated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"ended_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"end_reason":{"oneOf":[{"type":"string","enum":["released","superseded","registered","admin","not-verified","not-delegated","delegation-lost","grace-expired","registry-gone"]},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","domain","domain_unicode","state","expires_at","nameservers","delegation","registry","sensitive","seed_snapshot_id","last_check","verified_at","activated_at","ended_at","end_reason","created_at"],"additionalProperties":false}},"required":["claim"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The claim is no longer pending","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["dns"],"summary":"Drop the attached copy","description":"The zone then starts empty at activation. Charged `dns.manage` per request (unlike releasing the claim).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/tiers":{"get":{"responses":{"200":{"description":"Active tiers","content":{"application/json":{"schema":{"type":"object","properties":{"tiers":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"display_name":{"type":"string"},"vcpus":{"type":"integer"},"memory_mb":{"type":"integer"},"disk_gb":{"type":"integer"},"per_hour":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","display_name","vcpus","memory_mb","disk_gb","per_hour"],"additionalProperties":false}}},"required":["tiers"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"VPS tiers","description":"The purchasable server tiers with their hourly credit price (`per_hour`, from the active price book — see GET /credits/prices, contract `recurring.vps-hourly`; null means the tier cannot be ordered right now). Servers run in the EU; the region is not selectable. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/system-images":{"get":{"responses":{"200":{"description":"Allowlisted images","content":{"application/json":{"schema":{"type":"object","properties":{"system_images":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"display_name":{"type":"string"}},"required":["id","display_name"],"additionalProperties":false}}},"required":["system_images"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Bootable system images","description":"The allowlisted operating-system images. `id` is the value POST /vps/instances accepts as `image_ref` — raw provider image ids are rejected. Your own snapshots boot via their `create_ref` (see GET /vps/images). Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/ssh-keys":{"get":{"responses":{"200":{"description":"SSH keys","content":{"application/json":{"schema":{"type":"object","properties":{"ssh_keys":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"fingerprint":{"type":"string"},"created_at":{"type":"string"}},"required":["id","name","fingerprint","created_at"],"additionalProperties":false}}},"required":["ssh_keys"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"List SSH keys","description":"Your registered SSH public keys (public material only — the key body is never returned, just name and MD5 fingerprint). Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"public_key":{"type":"string"}},"required":["name","public_key"],"additionalProperties":false}}}},"responses":{"201":{"description":"Key registered","content":{"application/json":{"schema":{"type":"object","properties":{"ssh_key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"fingerprint":{"type":"string"},"created_at":{"type":"string"}},"required":["id","name","fingerprint","created_at"],"additionalProperties":false}},"required":["ssh_key"],"additionalProperties":false}}}},"400":{"description":"Malformed or unsupported public key, or missing name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"You already added a key with this fingerprint or name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Add an SSH key","description":"Registers an OpenSSH public key (`ssh-ed25519`, `ssh-rsa`, `ecdsa-sha2-*`, or FIDO `sk-*` types) for use at server create. Free.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/ssh-keys/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted"},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Delete an SSH key","description":"Removes the key from your account. Existing servers keep the keys they were created with.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/availability":{"get":{"responses":{"200":{"description":"Tier id → availability, plus the queued-create wait bound in hours","content":{"application/json":{"schema":{"type":"object","properties":{"availability":{"type":"object","additionalProperties":{"type":"boolean"}},"max_wait_hours":{"type":"integer"}},"required":["availability","max_wait_hours"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Tier availability","description":"Whether a create would find capacity right now, per active tier id: our platform capacity gate AND the provider's per-type location availability. Served from a short server-side cache (~60s) for display — POST /vps/instances always re-checks live, so treat `false` as \"expect the create to be refused (or queue it with `queue_if_unavailable`)\", not as a hard block. Unknown provider data reads as available. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances":{"get":{"responses":{"200":{"description":"Instances","content":{"application/json":{"schema":{"type":"object","properties":{"instances":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false}}},"required":["instances"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"List your servers","description":"Every VPS instance on the account, including deleted ones (history is kept). Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"tier_id":{"type":"string"},"name":{"type":"string","minLength":1},"ssh_key_ids":{"type":"array","items":{"type":"string"},"minItems":1},"image_ref":{"type":"string"},"volume_id":{"type":"string"},"queue_if_unavailable":{"type":"boolean"},"notify_on_outcome":{"type":"boolean"},"zone":{"type":"string"},"subdomain":{"type":"string"},"totp_code":{"type":"string"}},"required":["tier_id","name","ssh_key_ids"],"additionalProperties":false}}}},"responses":{"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"202":{"description":"Accepted. Normally the first hour is charged and provisioning starts asynchronously; a `queued` instance (capacity refusal + `queue_if_unavailable`) has charged nothing yet — the first hour is charged when provisioning actually starts","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"503":{"description":"VPS provisioning is unavailable (code `unavailable`) or platform capacity is temporarily full (code `capacity-unavailable`) — nothing inserted or charged; try again later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Volume not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The volume is attached to another server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"400":{"description":"Unknown tier or image, missing name, missing or unsynced SSH keys, or volume not available","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Create a server","description":"Enqueues a VPS create and answers 202 with the pending instance plus the action to poll (GET /vps/actions/{id}); IPs appear on the instance when it reaches `running`. Billing is hourly and prepaid: the first hour of the tier's `per_hour` price is charged up front, then every hour the server exists — running or not — until destroyed. If an hourly charge fails you are emailed and a grace window opens (24h by default); when it lapses the server is destroyed automatically. `image_ref` is a system image id (GET /vps/system-images) or the `create_ref` of one of your available snapshots (`image:<uuid>`); omitted it defaults to `ubuntu-24.04`. At least one SSH key is required. `volume_id` optionally mounts one of your available volumes as extra persistent storage — the server always boots from the tier's built-in disk. With `queue_if_unavailable` (volume-less creates only) a capacity refusal queues the create instead of answering 503: the instance comes back in state `queued`, retries until capacity frees (up to 24h by default), and the first hour is charged only when provisioning actually starts; cancel with DELETE /vps/instances/{id}. `notify_on_outcome` opts a queued create into an email when it finally provisions or gives up (toggle later via POST /vps/instances/{id}/queue-notify). Optional `zone` + `subdomain` anchor the server to a domain at create: the connection lands with the instance and the forward records are written after provisioning. Anchoring to a domain another customer shared with you through a `vps` grant runs the create DELEGATED — the server belongs to the domain owner, billed per the share's payer setting; a delegated create refuses `queue_if_unavailable` and `volume_id`, and a sensitive domain refuses delegates outright (`totp_code` serves the owner path's sensitive step-up).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/apps":{"get":{"responses":{"200":{"description":"Active apps","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The catalog app id, e.g. `ird_gitlab`"},"display_name":{"type":"string"},"description":{"oneOf":[{"type":"string"},{"type":"null"}]},"min_memory_mb":{"type":"integer"},"min_disk_gb":{"type":"integer"},"image_version":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"The golden image version new deployments boot"},"eligible_tier_ids":{"type":"array","items":{"type":"string"},"description":"Tier ids meeting the app's memory/disk/architecture minimums"}},"required":["id","display_name","description","min_memory_mb","min_disk_gb","image_version","eligible_tier_ids"],"additionalProperties":false}}},"required":["apps"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"One-click app catalog","description":"The apps available for one-click deployment onto a dedicated VPS, each with the golden image version new deployments boot and the tier ids meeting its minimums. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/apps/deployments":{"get":{"responses":{"200":{"description":"Deployments","content":{"application/json":{"schema":{"type":"object","properties":{"deployments":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"app_id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string","description":"The app's address; usable once `dns_state` is `ok` and the app finishes first boot"},"state":{"type":"string","enum":["provisioning","active","failed","deleted"]},"instance_id":{"type":"string"},"instance_state":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"The backing server's compute state (see GET /vps/instances)"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_state":{"type":"string","enum":["pending","ok","error"],"description":"The managed DNS record: `pending` while propagating, `ok` once the hostname resolves to the server, `error` with `dns_error` explaining"},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"password_available":{"type":"boolean","description":"True while the one-time root-password reveal (POST /vps/apps/deployments/{id}/reveal-password) is still unused"},"created_at":{"type":"string"}},"required":["id","app_id","hostname","url","state","instance_id","instance_state","ipv4","dns_state","dns_error","last_error","password_available","created_at"],"additionalProperties":false}}},"required":["deployments"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"List your app deployments","description":"Every one-click app deployment on the account (deleted ones excluded), joined with the backing server's compute state. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"app_id":{"type":"string","description":"A catalog id from GET /vps/apps"},"zone":{"type":"string","description":"A domain you own and DNS-host with ird, e.g. `exemplu.ro`"},"subdomain":{"type":"string","minLength":1,"description":"The label the app deploys at, e.g. `git` → `git.exemplu.ro`"},"tier_id":{"type":"string","description":"One of the app's `eligible_tier_ids`"},"ssh_key_ids":{"type":"array","items":{"type":"string"},"minItems":1},"name":{"type":"string","description":"Display name for the backing server; defaults to the hostname"},"queue_if_unavailable":{"type":"boolean","description":"When the tier has no capacity, queue the deploy instead of failing: the returned instance is `queued`, nothing is charged, and the platform retries until capacity frees or the wait bound (`queue_wait_hours`) passes"},"notify_on_outcome":{"type":"boolean","description":"Email when a queued deploy finally provisions or fails"},"totp_code":{"type":"string","description":"Authenticator step-up when the zone's domain is protected as sensitive"}},"required":["app_id","zone","subdomain","tier_id","ssh_key_ids"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — the first hour is charged and provisioning starts asynchronously (for a queued deploy the instance state is `queued` and the charge waits for capacity); poll the action, then the deployment's `dns_state`","content":{"application/json":{"schema":{"type":"object","properties":{"deployment":{"type":"object","properties":{"id":{"type":"string"},"app_id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string","description":"The app's address; usable once `dns_state` is `ok` and the app finishes first boot"},"state":{"type":"string","enum":["provisioning","active","failed","deleted"]},"instance_id":{"type":"string"},"instance_state":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"The backing server's compute state (see GET /vps/instances)"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_state":{"type":"string","enum":["pending","ok","error"],"description":"The managed DNS record: `pending` while propagating, `ok` once the hostname resolves to the server, `error` with `dns_error` explaining"},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"password_available":{"type":"boolean","description":"True while the one-time root-password reveal (POST /vps/apps/deployments/{id}/reveal-password) is still unused"},"created_at":{"type":"string"}},"required":["id","app_id","hostname","url","state","instance_id","instance_state","ipv4","dns_state","dns_error","last_error","password_available","created_at"],"additionalProperties":false},"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false},"root_password":{"type":"string","description":"The app's root password — shown here and, until used, via the one-time reveal endpoint; rotate it after first login"}},"required":["deployment","instance","action","root_password"],"additionalProperties":false}}}},"400":{"description":"Unknown/inactive app or tier, tier below the app's minimums, missing subdomain, invalid hostname, or the domain is not DNS-hosted with ird by you","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Profile incomplete, registrant email unverified (code `ownership-verification-required`), or sensitive-domain step-up required (`totp-required` / `invalid-totp` / `sensitive-domain-api-key-blocked`)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The hostname is already used by another deployment or a tunnel","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Provisioning unavailable, platform capacity full (unless `queue_if_unavailable`), or the app has no registered image right now — nothing inserted or charged","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Deploy an app","description":"One-click app deploy: creates a dedicated VPS from the app's prepared image, points `subdomain`.`zone` at it (an A record in your ird-hosted DNS zone, managed for you and healed if it drifts), and boots the app via cloud-init. `zone` must be a domain you DNS-host with ird and own; the record write faces the same gates as editing the zone directly (registrant-email ownership, and on a sensitive domain a `totp_code` step-up — API-key callers are refused there). Answers 202 with the deployment, the backing instance (billing is exactly a plain VPS at the tier's hourly price — no app surcharge), the action to poll, and — exactly once — `root_password`. Expect the app to be reachable at `url` a few minutes after the instance reaches `running` (DNS propagation + first boot; the TLS certificate issues automatically). For GitLab: log in as `root`, rotate the password on first login, and note git-over-SSH uses port 2222 (`ssh://git@<hostname>:2222/...`) — the server's own SSH (your keys) stays on 22. Password recovery without email: `sudo docker exec -it gitlab gitlab-rake \"gitlab:password:reset[root]\"` over SSH.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/apps/deployments/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Deployment","content":{"application/json":{"schema":{"type":"object","properties":{"deployment":{"type":"object","properties":{"id":{"type":"string"},"app_id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string","description":"The app's address; usable once `dns_state` is `ok` and the app finishes first boot"},"state":{"type":"string","enum":["provisioning","active","failed","deleted"]},"instance_id":{"type":"string"},"instance_state":{"oneOf":[{"type":"string"},{"type":"null"}],"description":"The backing server's compute state (see GET /vps/instances)"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_state":{"type":"string","enum":["pending","ok","error"],"description":"The managed DNS record: `pending` while propagating, `ok` once the hostname resolves to the server, `error` with `dns_error` explaining"},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"password_available":{"type":"boolean","description":"True while the one-time root-password reveal (POST /vps/apps/deployments/{id}/reveal-password) is still unused"},"created_at":{"type":"string"}},"required":["id","app_id","hostname","url","state","instance_id","instance_state","ipv4","dns_state","dns_error","last_error","password_available","created_at"],"additionalProperties":false},"instance":{"oneOf":[{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},{"type":"null"}]}},"required":["deployment","instance"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Get an app deployment","description":"The deployment with its backing instance. Destroying the app = destroying the instance (DELETE /vps/instances/{id}) — the managed DNS record is removed with it. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/apps/deployments/{id}/reveal-password":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The password — this response is the last time the platform can produce it","content":{"application/json":{"schema":{"type":"object","properties":{"root_password":{"type":"string"}},"required":["root_password"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Already revealed, or the deploy was cancelled/deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"The stored ciphertext no longer decrypts (platform key rotation) — reset over SSH","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Reveal an app deployment's root password (once)","description":"The one-time second chance at the root password the deploy response showed — for deploys that queued for capacity and finished after you left. Returns it and immediately discards the stored copy; every later call answers 409. Lost anyway? Reset over SSH: `sudo docker exec -it gitlab gitlab-rake \"gitlab:password:reset[root]\"`.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Instance","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false}},"required":["instance"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Get a server","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — deleting asynchronously","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Already deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Destroy a server","description":"Enqueues the delete and stops the hourly billing once it completes; attached volumes are released (and keep billing) rather than deleted. The server's disk contents are gone permanently — snapshot first if you need them. Idempotent: repeating the call while a delete is open returns the same action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/metrics":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"type","required":false,"schema":{"type":"string"}},{"in":"query","name":"start","required":false,"schema":{"type":"string"}},{"in":"query","name":"end","required":false,"schema":{"type":"string"}},{"in":"query","name":"step","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Labeled series of [timestamp value] points","content":{"application/json":{"schema":{"type":"object","properties":{"instance_id":{"type":"string"},"source":{"type":"string","enum":["live","stored"]},"start":{"type":"string"},"end":{"type":"string"},"step":{"type":"integer"},"series":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","enum":["cpu","disk-iops-read","disk-iops-write","disk-bandwidth-read","disk-bandwidth-write","net-pps-in","net-pps-out","net-bandwidth-in","net-bandwidth-out","traffic-out","traffic-in","traffic-included"]},"unit":{"type":"string","enum":["percent","iops","bytes/s","pps","bytes"]},"points":{"type":"array","items":{"type":"array","prefixItems":[{"type":"integer"},{"type":"number"}],"items":false},"description":"[unix-timestamp, value] pairs, oldest first; empty when nothing was recorded in the window"}},"required":["name","unit","points"],"additionalProperties":false}}},"required":["instance_id","source","start","end","step","series"],"additionalProperties":false}}}},"400":{"description":"Unknown type value, malformed start/end/step, or start not before end","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"VPS provisioning is unavailable (code `unavailable`) or platform capacity is temporarily full (code `capacity-unavailable`) — nothing inserted or charged; try again later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Server usage metrics","description":"Usage time series for a server. `type` is a comma-separated subset of `cpu`, `disk`, `network`, `traffic` (default `cpu,disk,network`); `start`/`end` are ISO-8601 instants (default: the last hour); `step` is the requested resolution in seconds, clamped so a response never exceeds ~500 points per series — the response's `step` is the effective value. Windows up to 7 days on a live server are served from the provider (`source` = `live`; per-user rate window, 429 when exceeded); longer windows, the `traffic` type, and deleted servers are served from our hourly samples (`source` = `stored`), downsampled to the clamped step (never finer than 3600). `traffic-out`/`traffic-in`/`traffic-included` are the provider's raw cumulative counters: they reset at the billing-period rollover and on server rebuild, so deltas computed across a reset come out negative. Charged `vps.metrics` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/queue-notify":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"}},"required":["enabled"],"additionalProperties":false}}}},"responses":{"200":{"description":"Toggled","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The create is no longer queued","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Toggle the queued-create outcome email","description":"Turns the outcome email of a queued create on or off: when enabled, you are emailed when the queued server finally provisions or gives up. Only valid while the instance is `queued`. Free.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/images":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1}},"required":["name"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — snapshotting asynchronously","content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"state":{"type":"string","enum":["pending","available","deleting","deleted","failed"]},"size_gb":{"oneOf":[{"type":"string"},{"type":"null"}]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"create_ref":{"type":"string"},"created_at":{"type":"string"}},"required":["id","name","state","size_gb","instance_id","subscription_id","create_ref","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["image","action"],"additionalProperties":false}}}},"400":{"description":"Server not running or stopped, or missing name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"VPS provisioning is unavailable (code `unavailable`) or platform capacity is temporarily full (code `capacity-unavailable`) — nothing inserted or charged; try again later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Snapshot a server","description":"Enqueues a snapshot of a running or stopped server. The image bills hourly by its size — `per_gb_hour` × GB (`recurring.image-hourly` on GET /credits/prices) — from the moment the snapshot completes until you delete it; its `create_ref` then boots new servers from it.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/restart":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — executing asynchronously; poll GET /vps/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"400":{"description":"Server is not running","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Another operation is already in progress on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Restart a server (graceful)","description":"Enqueues a graceful ACPI reboot of a running server. The guest OS shuts down cleanly and boots again; IPs and data are untouched, and the instance stays `running` throughout. For a hung server that ignores ACPI, use the hard reset instead. Charged the `vps.power` per-request price (0 at launch — see GET /credits/prices). Repeating the call while a restart is open returns the same action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/reset":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — executing asynchronously; poll GET /vps/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"400":{"description":"Server is not running","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Another operation is already in progress on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Force reset a server (hard)","description":"Enqueues a hard power cycle — like pressing the reset button: the OS gets no warning and unsaved data is lost. Use it to recover a hung server that ignores the graceful restart. The instance stays `running`. Charged the `vps.power` per-request price (0 at launch).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/shutdown":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — executing asynchronously; poll GET /vps/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"400":{"description":"Server is not running","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Another operation is already in progress on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Shut down a server (graceful)","description":"Enqueues a graceful ACPI shutdown. When the guest OS powers down (about 90 seconds are allowed) the instance enters `stopped`; if the OS ignores the signal the action fails and the server keeps running — use power-off to force it. A stopped server KEEPS BILLING hourly (it still reserves its resources) until you destroy it; power it back on with POST /vps/instances/{id}/power-on. Charged the `vps.power` per-request price (0 at launch).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/power-off":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — executing asynchronously; poll GET /vps/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"400":{"description":"Server is not running","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Another operation is already in progress on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Force power off a server (hard)","description":"Enqueues an immediate power cut — like pulling the plug: unsaved data is lost. Prefer the graceful shutdown; use this when the guest ignores it. The instance enters `stopped` and KEEPS BILLING hourly until you destroy it; power it back on with POST /vps/instances/{id}/power-on. Charged the `vps.power` per-request price (0 at launch).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/power-on":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — executing asynchronously; poll GET /vps/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"400":{"description":"Server is not stopped","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Another operation is already in progress on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Power on a stopped server","description":"Enqueues power-on for a `stopped` server; it boots with its IPs, disk, and mounted volumes intact and returns to `running`. Charged the `vps.power` per-request price (0 at launch).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/rdns":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ip":{"type":"string"},"hostname":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["ip","hostname"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — executing asynchronously; poll GET /vps/actions/{id}","content":{"application/json":{"schema":{"type":"object","properties":{"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["instance","action"],"additionalProperties":false}}}},"400":{"description":"IP is not one of the server's addresses, the hostname is invalid, or it does not forward-resolve to the IP","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Another operation is already in progress on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Set a server's reverse DNS (PTR)","description":"Enqueues a reverse DNS pointer change for one of the server's IPs: `ip` must be the server's IPv4 address or any address inside its IPv6 /64. The hostname must already forward-resolve to that exact IP (an A record for IPv4, AAAA for IPv6) — that forward-confirmed loop is what mail providers check (FCrDNS). Pass `hostname: null` to reset the PTR to the provider default. Works on running and stopped servers. Charged the `vps.rdns` per-request price (0 at launch — see GET /credits/prices). Repeating the call while the same change is open returns the same action.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/domains":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Connected domains","content":{"application/json":{"schema":{"type":"object","properties":{"connections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"hostname":{"type":"string"},"zone_origin":{"type":"string"},"rdns":{"type":"boolean"},"dns_state":{"type":"string","enum":["pending","ok","error"]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","instance_id","hostname","zone_origin","rdns","dns_state","dns_error","created_at"],"additionalProperties":false}}},"required":["connections"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"List a server's connected domains","description":"The domains connected to this server: each maintains managed A/AAAA records in your ird-hosted zone pointing the hostname at the server, and at most one (`rdns: true`) also drives the server's reverse DNS pointer — the forward-confirmed pair (FCrDNS) mail providers check. `dns_state` tracks the managed records: `pending` while the address propagates, `ok` once it publicly resolves, `error` with a reason in `dns_error`. Charged the `vps.reads` per-request price.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"zone":{"type":"string"},"subdomain":{"type":"string"},"set_rdns":{"type":"boolean"},"totp_code":{"type":"string"}},"required":["zone","subdomain"],"additionalProperties":false}}}},"responses":{"202":{"description":"Connected — records written; when the reverse pointer changes, poll the action","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string"},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"hostname":{"type":"string"},"zone_origin":{"type":"string"},"rdns":{"type":"boolean"},"dns_state":{"type":"string","enum":["pending","ok","error"]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","instance_id","hostname","zone_origin","rdns","dns_state","dns_error","created_at"],"additionalProperties":false},"instance":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"tier_id":{"type":"string"},"image_ref":{"type":"string"},"state":{"type":"string","enum":["pending","provisioning","running","stopped","deleting","deleted","failed","queued"]},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ipv6":{"oneOf":[{"type":"string"},{"type":"null"}]},"rdns":{"type":"object","additionalProperties":{"type":"string"},"description":"Reverse DNS pointers set through the API, keyed by IP; an IP absent here carries the provider default PTR"},"traffic":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}],"description":"Cumulative provider traffic counters in bytes (outgoing_bytes/ingoing_bytes/included_bytes + sampled_at), refreshed hourly; null until first sampled. Raw counters: they reset at the provider's billing-period rollover and on server rebuild, so deltas computed across a reset come out negative"},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"queue_notify":{"type":"boolean","description":"Only on queued instances (GET /vps/instances/{id}): whether the outcome email is on"},"queue_wait_hours":{"type":"integer","description":"Only on queued instances: how many hours the create keeps retrying before giving up"},"delegated":{"type":"boolean","description":"Present (true) on a server another account shared with this one through a vps grant (anchored to a granted domain): manageable here, billed per the share's payer setting (the owner by default)"},"created_at":{"type":"string"},"updated_at":{"type":"string"}},"required":["id","name","tier_id","image_ref","state","ipv4","ipv6","rdns","traffic","location","subscription_id","last_error","created_at","updated_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["connection","instance"],"additionalProperties":false}}}},"400":{"description":"Invalid subdomain, apex refused, zone not hosted on ird DNS, or the server has no public addresses","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Profile incomplete, registrant email unverified (code `ownership-verification-required`), or authenticator required/invalid for a sensitive domain (codes `totp-required` / `invalid-totp`)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The hostname is already used by an app deployment, a tunnel, or another connection — or another operation is in progress on this server","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Connect a domain to a server","description":"Points a subdomain of one of your ird-hosted zones at this server: A (and AAAA when the server has IPv6) records are written into your zone immediately, and — unless `set_rdns` is false — the server's reverse DNS pointer is set to the same hostname, completing the forward-confirmed pair (FCrDNS) that mail deliverability needs. The reverse pointer follows one hostname per server: a newer connection (or a manual reverse DNS change) takes it over. The zone must be hosted on your ird DNS, the hostname must be a subdomain (never the zone apex) and free of app deployments, tunnels, and other connections; a sensitive domain requires `totp_code`. The managed records are read-only in the zone editor while the connection lives (mutations answer 409) and are removed on disconnect. Charged the `vps.rdns` per-request price (0 at launch).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/domains/{connection-id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"connection-id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Disconnected; when a reverse pointer reset was enqueued, poll the action","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"type":"object","properties":{"id":{"type":"string"},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"hostname":{"type":"string"},"zone_origin":{"type":"string"},"rdns":{"type":"boolean"},"dns_state":{"type":"string","enum":["pending","ok","error"]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","instance_id","hostname","zone_origin","rdns","dns_state","dns_error","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["connection"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Disconnect a domain from a server","description":"Releases the connection: the managed A/AAAA records are removed from your zone (only if every value still targets this server — hand-made records survive), and when this connection was driving the server's reverse DNS pointer, a reset to the provider default is enqueued so the forward-confirmed pair never half-breaks silently. Charged the `vps.rdns` per-request price (0 at launch).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/instances/{id}/transfer":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"totp_code":{"type":"string"}},"required":["email"],"additionalProperties":false}}}},"responses":{"201":{"description":"Pending offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"400":{"description":"Invalid email, or no ird account with that email (error code email-unknown)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Missing/invalid authenticator code (error codes totp-required / invalid-totp), or the action is otherwise refused (ownership-verification-required)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The resource is in flight, its billing is in grace, or an offer is already pending","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Offer this server to another account","description":"Creates a pending handover offer for the server to `email` (an existing ird account); nothing moves until they accept. The resource must be settled with its billing in good standing — accrued debt never transfers. Session JWT only, and every offer demands a fresh authenticator (or backup) code in `totp_code`.","security":[{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cancelled offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Withdraw the pending server transfer offer","security":[{"accountJwt":[]}]}},"/vps/volumes/{id}/transfer":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"totp_code":{"type":"string"}},"required":["email"],"additionalProperties":false}}}},"responses":{"201":{"description":"Pending offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"400":{"description":"Invalid email, or no ird account with that email (error code email-unknown)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Missing/invalid authenticator code (error codes totp-required / invalid-totp), or the action is otherwise refused (ownership-verification-required)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The resource is in flight, its billing is in grace, or an offer is already pending","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Offer this volume to another account","description":"Creates a pending handover offer for the volume to `email` (an existing ird account); nothing moves until they accept. The resource must be settled with its billing in good standing — accrued debt never transfers. Session JWT only, and every offer demands a fresh authenticator (or backup) code in `totp_code`.","security":[{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cancelled offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Withdraw the pending volume transfer offer","security":[{"accountJwt":[]}]}},"/vps/images/{id}/transfer":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"totp_code":{"type":"string"}},"required":["email"],"additionalProperties":false}}}},"responses":{"201":{"description":"Pending offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"400":{"description":"Invalid email, or no ird account with that email (error code email-unknown)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Missing/invalid authenticator code (error codes totp-required / invalid-totp), or the action is otherwise refused (ownership-verification-required)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The resource is in flight, its billing is in grace, or an offer is already pending","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Offer this image to another account","description":"Creates a pending handover offer for the image to `email` (an existing ird account); nothing moves until they accept. The resource must be settled with its billing in good standing — accrued debt never transfers. Session JWT only, and every offer demands a fresh authenticator (or backup) code in `totp_code`.","security":[{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Cancelled offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Withdraw the pending image transfer offer","security":[{"accountJwt":[]}]}},"/vps/transfers":{"get":{"responses":{"200":{"description":"Pending offers","content":{"application/json":{"schema":{"type":"object","properties":{"incoming":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"outgoing":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}}},"required":["incoming","outgoing"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Pending handover offers, both directions","description":"Offers waiting on this account (`incoming`) and offers it made (`outgoing`), with the resource's name/state and the offering account's email joined. Session JWT only.","security":[{"accountJwt":[]}]}},"/vps/transfers/{id}/accept":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Accepted offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Missing/invalid authenticator code (error codes totp-required / invalid-totp), or the action is otherwise refused (ownership-verification-required)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The offer is no longer valid (resource moved, in flight, or billing in grace)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Take over the offered resource","description":"Moves the resource and its hourly subscriptions to this account in one transaction — an instance brings its attached volumes; from the next hourly bill on, this account pays. Requires a complete customer profile. For servers: the previous owner's SSH keys are still inside the machine — rotate credentials after taking over. Session JWT only, and every accept demands a fresh authenticator (or backup) code in `totp_code`.","security":[{"accountJwt":[]}]}},"/vps/transfers/{id}/decline":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Declined offer","content":{"application/json":{"schema":{"type":"object","properties":{"transfer":{"type":"object","properties":{"id":{"type":"string"},"resource_type":{"type":"string","enum":["instance","volume","image"]},"resource_id":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","declined","cancelled"]},"invited_email":{"type":"string"},"created_at":{"type":"string"},"resolved_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"type":"string"},"resource_state":{"type":"string"},"from_email":{"type":"string"}},"required":["id","resource_type","resource_id","state","invited_email","created_at","resolved_at"],"additionalProperties":false}},"required":["transfer"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["transfers"],"summary":"Decline an incoming transfer offer","security":[{"accountJwt":[]}]}},"/vps/volumes":{"get":{"responses":{"200":{"description":"Volumes","content":{"application/json":{"schema":{"type":"object","properties":{"volumes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"size_gb":{"type":"integer"},"state":{"type":"string","enum":["pending","available","attached","deleting","deleted","failed"]},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","name","size_gb","state","location","instance_id","subscription_id","last_error","created_at"],"additionalProperties":false}}},"required":["volumes"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"List your volumes","description":"Every block-storage volume on the account, including deleted ones. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1},"size_gb":{"type":"integer"}},"required":["name","size_gb"],"additionalProperties":false}}}},"responses":{"202":{"description":"Accepted — first hour charged, provisioning asynchronously","content":{"application/json":{"schema":{"type":"object","properties":{"volume":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"size_gb":{"type":"integer"},"state":{"type":"string","enum":["pending","available","attached","deleting","deleted","failed"]},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","name","size_gb","state","location","instance_id","subscription_id","last_error","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["volume","action"],"additionalProperties":false}}}},"400":{"description":"Missing name or size_gb out of range","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"VPS provisioning is unavailable (code `unavailable`) or platform capacity is temporarily full (code `capacity-unavailable`) — nothing inserted or charged; try again later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Create a volume","description":"Enqueues a block-storage volume create (10–10240 GB by default). Billing is hourly and prepaid: `per_gb_hour` × size (`recurring.volume-hourly` on GET /credits/prices), first hour charged up front, then every hour the volume exists until deleted — attached or not. Mount it at server create via `volume_id`; a volume mounts to one server at a time and is released when that server is destroyed.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/volumes/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — deleting asynchronously","content":{"application/json":{"schema":{"type":"object","properties":{"volume":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"size_gb":{"type":"integer"},"state":{"type":"string","enum":["pending","available","attached","deleting","deleted","failed"]},"location":{"oneOf":[{"type":"integer"},{"type":"null"}],"description":"Abstract location number; a volume only attaches to servers with the same location"},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"}},"required":["id","name","size_gb","state","location","instance_id","subscription_id","last_error","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["volume","action"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Attached to a server, or already deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Delete a volume","description":"Enqueues the delete for an unattached volume and stops its hourly billing once it completes; the data is gone permanently. Attached volumes cannot be deleted — destroy their server first. Idempotent while a delete is open.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/images":{"get":{"responses":{"200":{"description":"Snapshots","content":{"application/json":{"schema":{"type":"object","properties":{"images":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"state":{"type":"string","enum":["pending","available","deleting","deleted","failed"]},"size_gb":{"oneOf":[{"type":"string"},{"type":"null"}]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"create_ref":{"type":"string"},"created_at":{"type":"string"}},"required":["id","name","state","size_gb","instance_id","subscription_id","create_ref","created_at"],"additionalProperties":false}}},"required":["images"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"List your snapshots","description":"Every snapshot on the account, including deleted ones. `create_ref` is the `image_ref` value that boots a new server from the snapshot. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/images/{id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted — deleting asynchronously","content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"state":{"type":"string","enum":["pending","available","deleting","deleted","failed"]},"size_gb":{"oneOf":[{"type":"string"},{"type":"null"}]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"create_ref":{"type":"string"},"created_at":{"type":"string"}},"required":["id","name","state","size_gb","instance_id","subscription_id","create_ref","created_at"],"additionalProperties":false},"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["image","action"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Already deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Delete a snapshot","description":"Enqueues the delete and stops the snapshot's hourly billing once it completes.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/actions/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Action","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"result":{"oneOf":[{"type":"object","additionalProperties":{}},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","instance_id","error","result","created_at","finished_at"],"additionalProperties":false}},"required":["action"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Poll a VPS action","description":"Terminal states: `succeeded`, `failed` (a prepaid first-hour charge is refunded), `cancelled`. Everything else means the provider is still being worked — keep polling. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/vps/activity":{"get":{"parameters":[{"in":"query","name":"instance_id","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Activity","content":{"application/json":{"schema":{"type":"object","properties":{"activity":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["create","delete","create-image","delete-image","create-volume","delete-volume","restart","reset","shutdown","power-off","power-on","change-rdns"]},"state":{"type":"string","enum":["pending-charge","queued","claimed","submitted","reconciling","succeeded","failed","cancelled"]},"origin":{"type":"string","enum":["customer","grace","admin"]},"instance_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"resource_name":{"oneOf":[{"type":"string"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"type":"string"},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","type","state","origin","instance_id","resource_name","error","created_at","finished_at"],"additionalProperties":false}}},"required":["activity"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["vps"],"summary":"Infrastructure activity timeline","description":"The account's most recent VPS actions (up to 100), newest first, with the affected resource's name and who initiated each: `customer` (you), `grace` (automatic destroy after the billing grace window lapsed), or `admin`. Pass `instance_id` to narrow the timeline to one server. Charged `vps.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/tunnels":{"get":{"responses":{"200":{"description":"Tunnels","content":{"application/json":{"schema":{"type":"object","properties":{"tunnels":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"status":{"type":"string","enum":["pending-dns","provisioning","active","degraded","failed","deleting"]},"transport":{"type":"string"},"port":{"type":"integer"},"node":{"oneOf":[{"type":"object","properties":{"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ssh_host":{"type":"string"},"ssh_port":{"type":"integer"},"ssh_user":{"type":"string"}},"required":["ipv4","ssh_host","ssh_port","ssh_user"],"additionalProperties":false},{"type":"null"}]},"ssh_command":{"oneOf":[{"type":"string"},{"type":"null"}]},"settings":{"description":"Customer-tunable per-tunnel settings. `offline_ipns` (optional) holds the id of one of your IPNS names (`GET /ipfs/names`) — while your device is offline the tunnel serves that name's published content instead of the shared offline page.","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_cname_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"client_connected":{"type":"boolean"},"last_error":{"description":"Customer-facing summary of the last provisioning error, if any.","oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a tunnel living on a domain another account shared with this one through a tunnel grant: manageable here, billed per the share's payer setting (the owner by default).","type":"boolean"}},"required":["id","hostname","url","state","status","transport","port","node","ssh_command","settings","dns_ok","dns_error","dns_target","dns_cname_target","cert_status","client_connected","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}}},"required":["tunnels"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["tunnels"],"summary":"List your tunnels","description":"Every non-deleted HTTPS tunnel on the account. `status` is the customer-facing view: an `active` tunnel whose device is not currently connected reads `degraded`. Charged `tunnel.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"hostname":{"type":"string"},"ssh_public_key":{"type":"string"},"ssh_key_id":{"type":"string"},"transport":{"type":"string","enum":["ssh-v1"]},"settings":{"description":"Per-tunnel settings; unknown keys are rejected. `offline_ipns` points the tunnel's offline page at one of your IPNS names (by id or label; stored as the id).","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"totp_code":{"type":"string"}},"required":["hostname"],"additionalProperties":false}}}},"responses":{"201":{"description":"Tunnel created (first hour charged)","content":{"application/json":{"schema":{"type":"object","properties":{"tunnel":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"status":{"type":"string","enum":["pending-dns","provisioning","active","degraded","failed","deleting"]},"transport":{"type":"string"},"port":{"type":"integer"},"node":{"oneOf":[{"type":"object","properties":{"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ssh_host":{"type":"string"},"ssh_port":{"type":"integer"},"ssh_user":{"type":"string"}},"required":["ipv4","ssh_host","ssh_port","ssh_user"],"additionalProperties":false},{"type":"null"}]},"ssh_command":{"oneOf":[{"type":"string"},{"type":"null"}]},"settings":{"description":"Customer-tunable per-tunnel settings. `offline_ipns` (optional) holds the id of one of your IPNS names (`GET /ipfs/names`) — while your device is offline the tunnel serves that name's published content instead of the shared offline page.","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_cname_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"client_connected":{"type":"boolean"},"last_error":{"description":"Customer-facing summary of the last provisioning error, if any.","oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a tunnel living on a domain another account shared with this one through a tunnel grant: manageable here, billed per the share's payer setting (the owner by default).","type":"boolean"}},"required":["id","hostname","url","state","status","transport","port","node","ssh_command","settings","dns_ok","dns_error","dns_target","dns_cname_target","cert_status","client_connected","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["tunnel"],"additionalProperties":false}}}},"400":{"description":"Invalid hostname, key, transport or settings; both or neither of ssh_public_key/ssh_key_id; ssh_key_id not on your account; or pricing not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Profile incomplete, or registrant verification required for an ird-registered domain. Domains marked sensitive demand a fresh authenticator code in `totp_code` (error codes totp-required / invalid-totp) and refuse API keys (sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The hostname already has a tunnel","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Tunnel capacity is temporarily full","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["tunnels"],"summary":"Create a tunnel","description":"Provisions an HTTPS tunnel on your own domain or subdomain: a node and local port are allocated, the first prepaid hour is charged (`recurring.tunnel-hourly` — billing continues hourly, into a negative balance if needed, until you delete the tunnel), and the response carries the `ssh_command` your device runs plus the DNS targets: on a subdomain point a CNAME record at `dns_cname_target` (the node hostname — survives node IP changes), on a root domain point an A record at `dns_target` (the node IP). Provide exactly one of `ssh_public_key` (an OpenSSH public key line) or `ssh_key_id` (the id of a key saved via POST /vps/ssh-keys — list them with GET /vps/ssh-keys). Domains hosted on ird DNS get the record created automatically (CNAME on a subdomain, A at the apex) and cleaned up when the tunnel is deleted; ird-registered domains must pass registrant verification. The tunnel goes live once DNS resolves to the node and the certificate is issued.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/tunnels/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Tunnel","content":{"application/json":{"schema":{"type":"object","properties":{"tunnel":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"status":{"type":"string","enum":["pending-dns","provisioning","active","degraded","failed","deleting"]},"transport":{"type":"string"},"port":{"type":"integer"},"node":{"oneOf":[{"type":"object","properties":{"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ssh_host":{"type":"string"},"ssh_port":{"type":"integer"},"ssh_user":{"type":"string"}},"required":["ipv4","ssh_host","ssh_port","ssh_user"],"additionalProperties":false},{"type":"null"}]},"ssh_command":{"oneOf":[{"type":"string"},{"type":"null"}]},"settings":{"description":"Customer-tunable per-tunnel settings. `offline_ipns` (optional) holds the id of one of your IPNS names (`GET /ipfs/names`) — while your device is offline the tunnel serves that name's published content instead of the shared offline page.","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_cname_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"client_connected":{"type":"boolean"},"last_error":{"description":"Customer-facing summary of the last provisioning error, if any.","oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a tunnel living on a domain another account shared with this one through a tunnel grant: manageable here, billed per the share's payer setting (the owner by default).","type":"boolean"}},"required":["id","hostname","url","state","status","transport","port","node","ssh_command","settings","dns_ok","dns_error","dns_target","dns_cname_target","cert_status","client_connected","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["tunnel"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["tunnels"],"summary":"Tunnel detail","description":"One tunnel with its connection info and live status. Charged `tunnel.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"totp_code":{"type":"string"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Tunnel now deleting","content":{"application/json":{"schema":{"type":"object","properties":{"tunnel":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"status":{"type":"string","enum":["pending-dns","provisioning","active","degraded","failed","deleting"]},"transport":{"type":"string"},"port":{"type":"integer"},"node":{"oneOf":[{"type":"object","properties":{"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ssh_host":{"type":"string"},"ssh_port":{"type":"integer"},"ssh_user":{"type":"string"}},"required":["ipv4","ssh_host","ssh_port","ssh_user"],"additionalProperties":false},{"type":"null"}]},"ssh_command":{"oneOf":[{"type":"string"},{"type":"null"}]},"settings":{"description":"Customer-tunable per-tunnel settings. `offline_ipns` (optional) holds the id of one of your IPNS names (`GET /ipfs/names`) — while your device is offline the tunnel serves that name's published content instead of the shared offline page.","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_cname_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"client_connected":{"type":"boolean"},"last_error":{"description":"Customer-facing summary of the last provisioning error, if any.","oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a tunnel living on a domain another account shared with this one through a tunnel grant: manageable here, billed per the share's payer setting (the owner by default).","type":"boolean"}},"required":["id","hostname","url","state","status","transport","port","node","ssh_command","settings","dns_ok","dns_error","dns_target","dns_cname_target","cert_status","client_connected","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["tunnel"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Profile incomplete; on a sensitive domain, missing/invalid authenticator code or an API-key caller (error codes totp-required / invalid-totp / sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["tunnels"],"summary":"Delete a tunnel","description":"Stops billing immediately and tears the tunnel down on the node's next poll. Free — a negative balance never blocks stopping the tunnel that is billing you. Idempotent while deletion is in progress.","security":[{"apiKey":[]},{"accountJwt":[]}]},"patch":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"settings":{"description":"The complete desired settings object.","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"totp_code":{"type":"string"}},"required":["settings"],"additionalProperties":false}}}},"responses":{"200":{"description":"Tunnel with the new settings","content":{"application/json":{"schema":{"type":"object","properties":{"tunnel":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"status":{"type":"string","enum":["pending-dns","provisioning","active","degraded","failed","deleting"]},"transport":{"type":"string"},"port":{"type":"integer"},"node":{"oneOf":[{"type":"object","properties":{"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ssh_host":{"type":"string"},"ssh_port":{"type":"integer"},"ssh_user":{"type":"string"}},"required":["ipv4","ssh_host","ssh_port","ssh_user"],"additionalProperties":false},{"type":"null"}]},"ssh_command":{"oneOf":[{"type":"string"},{"type":"null"}]},"settings":{"description":"Customer-tunable per-tunnel settings. `offline_ipns` (optional) holds the id of one of your IPNS names (`GET /ipfs/names`) — while your device is offline the tunnel serves that name's published content instead of the shared offline page.","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_cname_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"client_connected":{"type":"boolean"},"last_error":{"description":"Customer-facing summary of the last provisioning error, if any.","oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a tunnel living on a domain another account shared with this one through a tunnel grant: manageable here, billed per the share's payer setting (the owner by default).","type":"boolean"}},"required":["id","hostname","url","state","status","transport","port","node","ssh_command","settings","dns_ok","dns_error","dns_target","dns_cname_target","cert_status","client_connected","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["tunnel"],"additionalProperties":false}}}},"400":{"description":"Invalid settings object, unknown key, or offline_ipns not one of your creating/active IPNS names","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Profile incomplete; on a sensitive domain, missing/invalid authenticator code or an API-key caller (error codes totp-required / invalid-totp / sensitive-domain-api-key-blocked)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The tunnel is being deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["tunnels"],"summary":"Update tunnel settings","description":"Replaces the tunnel's `settings` object (full-object replace through the allowlist — send the complete desired object; omitting a key clears it). Currently one key is defined: `offline_ipns` — the id or label of one of your IPNS names (`GET /ipfs/names`); while your device is offline the tunnel then serves that name's published content instead of the shared offline page (the node picks the change up within one poll once the name is active). Clear it by sending `{\"settings\": {}}`. Charged `tunnel.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/tunnels/{id}/verify-dns":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Check result on the tunnel","content":{"application/json":{"schema":{"type":"object","properties":{"tunnel":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"url":{"type":"string"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"status":{"type":"string","enum":["pending-dns","provisioning","active","degraded","failed","deleting"]},"transport":{"type":"string"},"port":{"type":"integer"},"node":{"oneOf":[{"type":"object","properties":{"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]},"ssh_host":{"type":"string"},"ssh_port":{"type":"integer"},"ssh_user":{"type":"string"}},"required":["ipv4","ssh_host","ssh_port","ssh_user"],"additionalProperties":false},{"type":"null"}]},"ssh_command":{"oneOf":[{"type":"string"},{"type":"null"}]},"settings":{"description":"Customer-tunable per-tunnel settings. `offline_ipns` (optional) holds the id of one of your IPNS names (`GET /ipfs/names`) — while your device is offline the tunnel serves that name's published content instead of the shared offline page.","type":"object","properties":{"offline_ipns":{"type":"string"}},"additionalProperties":false},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"dns_cname_target":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"client_connected":{"type":"boolean"},"last_error":{"description":"Customer-facing summary of the last provisioning error, if any.","oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a tunnel living on a domain another account shared with this one through a tunnel grant: manageable here, billed per the share's payer setting (the owner by default).","type":"boolean"}},"required":["id","hostname","url","state","status","transport","port","node","ssh_command","settings","dns_ok","dns_error","dns_target","dns_cname_target","cert_status","client_connected","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["tunnel"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["tunnels"],"summary":"Re-check DNS","description":"Re-verifies that the tunnel hostname resolves to its node's IP (run it after fixing your records — a pass also retries a failed certificate). Charged `tunnel.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/pins":{"get":{"parameters":[{"in":"query","name":"status","required":false,"schema":{"type":"string"},"description":"Comma-separated of awaiting-upload|queued|pinning|pinned|failed|deleting"},{"in":"query","name":"q","required":false,"schema":{"type":"string"},"description":"Name substring (case-insensitive) or CID prefix"},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"1–100, default 25"},{"in":"query","name":"offset","required":false,"schema":{"type":"integer"},"description":"Rows to skip, default 0"}],"responses":{"200":{"description":"Pins page","content":{"application/json":{"schema":{"type":"object","properties":{"pins":{"type":"array","items":{"type":"object","properties":{"id":{"description":"Pin id — also the Pinning Service API requestid.","type":"string"},"cid":{"description":"Null while a direct upload has not delivered bytes yet.","oneOf":[{"type":"string"},{"type":"null"}]},"cid_v1":{"description":"The CID's base32 CIDv1 spelling — the form gateway URLs carry.","oneOf":[{"type":"string"},{"type":"null"}]},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["awaiting-upload","queued","pinning","pinned","failed","deleting"]},"size_bytes":{"oneOf":[{"type":"integer"},{"type":"null"}]},"gateway_url":{"description":"Where the pinned content serves once fetched.","oneOf":[{"type":"string"},{"type":"null"}]},"meta":{"type":"object","additionalProperties":{"type":"string"}},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"description":"Customer-facing summary of the last node error, if any.","oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","cid","cid_v1","name","state","size_bytes","gateway_url","meta","created_at","updated_at","last_error"],"additionalProperties":false}},"total":{"description":"Match count across all pages","type":"integer"}},"required":["pins","total"],"additionalProperties":false}}}},"400":{"description":"Invalid status, q, limit or offset","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"List your pins","description":"Non-deleted pins on the account, newest first, paged — `total` is the full match count so clients can render page controls. `status` filters on a comma-separated list of states; `q` searches case-insensitively in the pin name (substring) or as an exact prefix of the CID (either spelling). Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cid":{"type":"string"},"name":{"type":"string","maxLength":255},"origins":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","additionalProperties":{"type":"string"}}},"required":["cid"],"additionalProperties":false}}}},"responses":{"202":{"description":"Pin queued","content":{"application/json":{"schema":{"type":"object","properties":{"pin":{"type":"object","properties":{"id":{"description":"Pin id — also the Pinning Service API requestid.","type":"string"},"cid":{"description":"Null while a direct upload has not delivered bytes yet.","oneOf":[{"type":"string"},{"type":"null"}]},"cid_v1":{"description":"The CID's base32 CIDv1 spelling — the form gateway URLs carry.","oneOf":[{"type":"string"},{"type":"null"}]},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["awaiting-upload","queued","pinning","pinned","failed","deleting"]},"size_bytes":{"oneOf":[{"type":"integer"},{"type":"null"}]},"gateway_url":{"description":"Where the pinned content serves once fetched.","oneOf":[{"type":"string"},{"type":"null"}]},"meta":{"type":"object","additionalProperties":{"type":"string"}},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"description":"Customer-facing summary of the last node error, if any.","oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","cid","cid_v1","name","state","size_bytes","gateway_url","meta","created_at","updated_at","last_error"],"additionalProperties":false}},"required":["pin"],"additionalProperties":false}}}},"400":{"description":"Malformed CID, name, origins or meta; pin limit reached; or pricing not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Pin capacity is temporarily full","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Pin by CID","description":"Asks the service to fetch and pin existing IPFS content by CID (CIDv0 `Qm…` or CIDv1 base32/base36/base58). Async — the response is `202` with the pin `queued`; poll `GET /ipfs/pins/{id}` until `pinned` or `failed`. Storage bills hourly per pinned MiB (`recurring.ipfs-pin-hourly`, prepaid from credits — hard-funded: creation is refused at a non-positive balance or while the storage subscription is in grace) plus gateway egress per MiB served. `origins` (≤20 multiaddrs) are hints the node tries first; `meta` (string map, ≤1000 keys) is stored verbatim.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/pins/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pin","content":{"application/json":{"schema":{"type":"object","properties":{"pin":{"type":"object","properties":{"id":{"description":"Pin id — also the Pinning Service API requestid.","type":"string"},"cid":{"description":"Null while a direct upload has not delivered bytes yet.","oneOf":[{"type":"string"},{"type":"null"}]},"cid_v1":{"description":"The CID's base32 CIDv1 spelling — the form gateway URLs carry.","oneOf":[{"type":"string"},{"type":"null"}]},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["awaiting-upload","queued","pinning","pinned","failed","deleting"]},"size_bytes":{"oneOf":[{"type":"integer"},{"type":"null"}]},"gateway_url":{"description":"Where the pinned content serves once fetched.","oneOf":[{"type":"string"},{"type":"null"}]},"meta":{"type":"object","additionalProperties":{"type":"string"}},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"description":"Customer-facing summary of the last node error, if any.","oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","cid","cid_v1","name","state","size_bytes","gateway_url","meta","created_at","updated_at","last_error"],"additionalProperties":false}},"required":["pin"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Pin detail","description":"One pin with its live state and gateway URL. Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Pin now deleting","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Unpin","description":"Stops billing immediately and unpins on the node's next poll. Free — a negative balance never blocks removing what bills you. Idempotent while deletion is in progress.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/uploads":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":255},"meta":{"type":"object","additionalProperties":{"type":"string"}},"format":{"type":"string","enum":["file","car"]}},"additionalProperties":false}}}},"responses":{"201":{"description":"Upload grant issued","content":{"application/json":{"schema":{"type":"object","properties":{"upload":{"type":"object","properties":{"id":{"type":"string"},"pin_id":{"type":"string"},"url":{"description":"Direct node URL to POST the raw bytes to (append ?format=car for CAR archives).","type":"string"},"token":{"description":"Bearer token for the upload POST; present while the grant is usable.","oneOf":[{"type":"string"},{"type":"null"}]},"max_bytes":{"type":"integer"},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["issued","completed","failed","expired"]},"cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"size_bytes":{"oneOf":[{"type":"integer"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","pin_id","url","token","max_bytes","expires_at","status","cid","size_bytes","error"],"additionalProperties":false}},"required":["upload"],"additionalProperties":false}}}},"400":{"description":"Invalid name or meta; pin limit reached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits to cover the up-front charge","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Pin capacity temporarily full, or upload grants unavailable","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Start a direct upload","description":"Issues a short-lived single-use grant to upload file bytes straight to a storage node (large content never streams through this API). POST the raw bytes to the returned `url` with `Authorization: Bearer <token>` (append `?format=car` for a client-packed CAR archive — that is also how directories upload). The response includes the associated pin id (`pin_id`, state `awaiting-upload`); once the node ingests the bytes the pin fills with the CID and flips to `pinned`. Same funding gates as pinning by CID.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/uploads/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Upload","content":{"application/json":{"schema":{"type":"object","properties":{"upload":{"type":"object","properties":{"id":{"type":"string"},"pin_id":{"type":"string"},"url":{"description":"Direct node URL to POST the raw bytes to (append ?format=car for CAR archives).","type":"string"},"token":{"description":"Bearer token for the upload POST; present while the grant is usable.","oneOf":[{"type":"string"},{"type":"null"}]},"max_bytes":{"type":"integer"},"expires_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["issued","completed","failed","expired"]},"cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"size_bytes":{"oneOf":[{"type":"integer"},{"type":"null"}]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","pin_id","url","token","max_bytes","expires_at","status","cid","size_bytes","error"],"additionalProperties":false}},"required":["upload"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Upload status","description":"The grant's status (`issued`/`completed`/`failed`/`expired`) and, once completed, the resulting CID and size. Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/names":{"get":{"responses":{"200":{"description":"Names","content":{"application/json":{"schema":{"type":"object","properties":{"names":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"name":{"description":"The k51… IPNS name; null until the node generates the key.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["creating","active","failed","deleting"]},"target_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"target_url":{"description":"Gateway entry for the content the name currently points at (`<gateway>/ipfs/<cid>`, taken from `last_published_cid` and falling back to `target_cid`); null until the name has a target. It moves with every publish — link to `url` for an address that does not.","oneOf":[{"type":"string"},{"type":"null"}]},"url":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","label","name","state","target_cid","last_published_cid","last_published_at","target_url","url","last_error","created_at","updated_at"],"additionalProperties":false}}},"required":["names"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"List your IPNS names","description":"Every non-deleted IPNS name on the account. Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"description":"A hostname on (or under) one of your ird DNS zones: dot-separated labels of [a-z0-9-], ≤253 chars, unique per account","type":"string"},"serve":{"description":"Also attach the hostname as a linked gateway domain and create its DNS records","type":"boolean"}},"required":["label"],"additionalProperties":false}}}},"responses":{"201":{"description":"Name creating (+ the linked domain when serve was requested)","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"name":{"description":"The k51… IPNS name; null until the node generates the key.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["creating","active","failed","deleting"]},"target_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"target_url":{"description":"Gateway entry for the content the name currently points at (`<gateway>/ipfs/<cid>`, taken from `last_published_cid` and falling back to `target_cid`); null until the name has a target. It moves with every publish — link to `url` for an address that does not.","oneOf":[{"type":"string"},{"type":"null"}]},"url":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","label","name","state","target_cid","last_published_cid","last_published_at","target_url","url","last_error","created_at","updated_at"],"additionalProperties":false},"domain":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"ipns_name_id":{"description":"Set when the domain is linked to one of your IPNS names — its DNS records (A + `_dnslink` TXT) are then created and maintained for you.","oneOf":[{"type":"string"},{"type":"null"}]},"pin_count":{"description":"Live pins the domain serves at `/ipfs/<cid>` (unbounded — the pins themselves ride the paged `GET /ipfs/domains/{id}/pins`).","type":"integer"},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dnslink_hint":{"description":"The TXT record to create on your ird-hosted zone (`ird dns set-record` or the DNS panel). Ignore it on linked rows (`ipns_name_id` set) — the record is managed for you.","type":"string"},"dns_target":{"description":"The gateway node's IPv4 the domain's A record must point at — present on the create response (manual-mapping rows need it to set the A record; linked/pins rows get the record created for them). Any AAAA record at the hostname must be removed (on ird-managed rows it is removed for you): the gateway serves IPv4 only and certificate validation prefers IPv6.","type":"string"},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a gateway domain under a domain another account shared with this one through an ipfs grant: manageable here, billed per the share's payer setting (the owner by default); gateway egress always bills the owner.","type":"boolean"}},"required":["id","domain","state","ipns_name_id","pin_count","last_error","dnslink_hint","verified_at","created_at","updated_at"],"additionalProperties":false}},"required":["name"],"additionalProperties":false}}}},"400":{"description":"Invalid label, name/domain limit reached, or the hostname is not on your ird DNS","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"You already have a name with this label (or one deriving the same key name), or the domain is already attached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Capacity temporarily full","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Create an IPNS name","description":"Creates a customer-owned IPNS name (a stable address whose target CID you can re-publish). The label is a hostname that must be — or sit under — a DNS zone hosted on your ird account (`GET /dns/domains`); ownership is verified against your zones. Async — the node generates the key (escrowed control-plane-side, so it survives node loss) and the `k51…` name appears when it first reports. Point it at content with `PUT /ipfs/names/{id}/target`. With `serve: true` the hostname is also attached as a linked gateway domain on the same node and its DNS records (A now, `_dnslink` TXT once the `k51…` exists) are created on your zone for you — the response then carries the created `domain` alongside the `name`. Requires a positive credit balance (gateway egress bills per MiB served).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/names/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Name","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"name":{"description":"The k51… IPNS name; null until the node generates the key.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["creating","active","failed","deleting"]},"target_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"target_url":{"description":"Gateway entry for the content the name currently points at (`<gateway>/ipfs/<cid>`, taken from `last_published_cid` and falling back to `target_cid`); null until the name has a target. It moves with every publish — link to `url` for an address that does not.","oneOf":[{"type":"string"},{"type":"null"}]},"url":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","label","name","state","target_cid","last_published_cid","last_published_at","target_url","url","last_error","created_at","updated_at"],"additionalProperties":false}},"required":["name"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"IPNS name detail","description":"One IPNS name with its publish state. Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Name now deleting","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"A tunnel still references this name","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Delete an IPNS name","description":"Removes the name and its key from the node (the escrowed key copy is retained). Best-effort removes the `_dnslink` TXT of any gateway domain linked to the name (the domain itself stays attached — detach it separately). Refused with 409 while a tunnel still uses the name for its offline page. Free; idempotent while deleting.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/names/{id}/target":{"put":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cid":{"type":"string"}},"required":["cid"],"additionalProperties":false}}}},"responses":{"200":{"description":"Target set","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"name":{"description":"The k51… IPNS name; null until the node generates the key.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["creating","active","failed","deleting"]},"target_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_published_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"target_url":{"description":"Gateway entry for the content the name currently points at (`<gateway>/ipfs/<cid>`, taken from `last_published_cid` and falling back to `target_cid`); null until the name has a target. It moves with every publish — link to `url` for an address that does not.","oneOf":[{"type":"string"},{"type":"null"}]},"url":{"oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","label","name","state","target_cid","last_published_cid","last_published_at","target_url","url","last_error","created_at","updated_at"],"additionalProperties":false}},"required":["name"],"additionalProperties":false}}}},"400":{"description":"Malformed CID","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Publish a new target","description":"Points the name at a CID; the node re-publishes on its next poll (and kubo auto-republishes to keep the record alive). The content should be pinned on the account or the gateway will serve nothing for it.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/domains":{"get":{"responses":{"200":{"description":"Domains","content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"ipns_name_id":{"description":"Set when the domain is linked to one of your IPNS names — its DNS records (A + `_dnslink` TXT) are then created and maintained for you.","oneOf":[{"type":"string"},{"type":"null"}]},"pin_count":{"description":"Live pins the domain serves at `/ipfs/<cid>` (unbounded — the pins themselves ride the paged `GET /ipfs/domains/{id}/pins`).","type":"integer"},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dnslink_hint":{"description":"The TXT record to create on your ird-hosted zone (`ird dns set-record` or the DNS panel). Ignore it on linked rows (`ipns_name_id` set) — the record is managed for you.","type":"string"},"dns_target":{"description":"The gateway node's IPv4 the domain's A record must point at — present on the create response (manual-mapping rows need it to set the A record; linked/pins rows get the record created for them). Any AAAA record at the hostname must be removed (on ird-managed rows it is removed for you): the gateway serves IPv4 only and certificate validation prefers IPv6.","type":"string"},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a gateway domain under a domain another account shared with this one through an ipfs grant: manageable here, billed per the share's payer setting (the owner by default); gateway egress always bills the owner.","type":"boolean"}},"required":["id","domain","state","ipns_name_id","pin_count","last_error","dnslink_hint","verified_at","created_at","updated_at"],"additionalProperties":false}}},"required":["domains"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"List your gateway domains","description":"Customer-owned domains serving your pinned content through the gateway, unbranded. Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"ipns_name_id":{"description":"Link the domain to this IPNS name of yours and auto-create its DNS records","type":"string"},"pin_ids":{"description":"Your own live pins to serve at /ipfs/<cid> on the domain right away — any node, any count (content on other nodes replicates to the domain's node). Manage later via POST /ipfs/domains/{id}/pins.","type":"array","items":{"type":"string"}}},"required":["domain"],"additionalProperties":false}}}},"responses":{"201":{"description":"Domain pending verification","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"ipns_name_id":{"description":"Set when the domain is linked to one of your IPNS names — its DNS records (A + `_dnslink` TXT) are then created and maintained for you.","oneOf":[{"type":"string"},{"type":"null"}]},"pin_count":{"description":"Live pins the domain serves at `/ipfs/<cid>` (unbounded — the pins themselves ride the paged `GET /ipfs/domains/{id}/pins`).","type":"integer"},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dnslink_hint":{"description":"The TXT record to create on your ird-hosted zone (`ird dns set-record` or the DNS panel). Ignore it on linked rows (`ipns_name_id` set) — the record is managed for you.","type":"string"},"dns_target":{"description":"The gateway node's IPv4 the domain's A record must point at — present on the create response (manual-mapping rows need it to set the A record; linked/pins rows get the record created for them). Any AAAA record at the hostname must be removed (on ird-managed rows it is removed for you): the gateway serves IPv4 only and certificate validation prefers IPv6.","type":"string"},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a gateway domain under a domain another account shared with this one through an ipfs grant: manageable here, billed per the share's payer setting (the owner by default); gateway egress always bills the owner.","type":"boolean"}},"required":["id","domain","state","ipns_name_id","pin_count","last_error","dnslink_hint","verified_at","created_at","updated_at"],"additionalProperties":false}},"required":["domain"],"additionalProperties":false}}}},"400":{"description":"Invalid domain, domain limit reached, or the domain is not hosted on your ird DNS","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The domain is already attached","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Capacity temporarily full","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Attach your own domain","description":"Serves your content from a domain you own, with no ird branding. The domain must be — or be a subdomain of — a DNS zone hosted on your ird account (`GET /dns/domains`): ownership is verified against your zones, and service hosts (the gateway and its aliases, node hostnames) are never attachable. With `ipns_name_id` (one of your IPNS names, creating or active) the domain is linked to that name, pinned to its node, and the DNS records are created on your zone for you — the A immediately, the `_dnslink` TXT once the name has its `k51…`. Without it you own the mapping: point the domain's A/CNAME at the gateway (the response's `dns_target` is the address) and create the `_dnslink` TXT from `dnslink_hint` on that zone (`dnslink=/ipns/<your k51… name>` or `dnslink=/ipfs/<cid>`) — one `ird dns set-record` or DNS-panel edit. Remove any AAAA record at the hostname (ird-managed rows have it removed for you): the gateway serves IPv4 only and certificate validation prefers IPv6, so a stale AAAA blocks issuance. The referenced content must be pinned on the account. `pin_ids` (optional, any count) attaches your own live pins immediately — the domain then serves each at `/ipfs/<cid>` (only attached pins; everything else 404s). Pins may live on any ird node: the domain binds to the node holding most of the bytes and the rest is replicated onto it automatically (503 `capacity-unavailable` when that node has no room). Requires a positive credit balance (gateway egress bills per MiB served).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/domains/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"ipns_name_id":{"description":"Set when the domain is linked to one of your IPNS names — its DNS records (A + `_dnslink` TXT) are then created and maintained for you.","oneOf":[{"type":"string"},{"type":"null"}]},"pin_count":{"description":"Live pins the domain serves at `/ipfs/<cid>` (unbounded — the pins themselves ride the paged `GET /ipfs/domains/{id}/pins`).","type":"integer"},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dnslink_hint":{"description":"The TXT record to create on your ird-hosted zone (`ird dns set-record` or the DNS panel). Ignore it on linked rows (`ipns_name_id` set) — the record is managed for you.","type":"string"},"dns_target":{"description":"The gateway node's IPv4 the domain's A record must point at — present on the create response (manual-mapping rows need it to set the A record; linked/pins rows get the record created for them). Any AAAA record at the hostname must be removed (on ird-managed rows it is removed for you): the gateway serves IPv4 only and certificate validation prefers IPv6.","type":"string"},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a gateway domain under a domain another account shared with this one through an ipfs grant: manageable here, billed per the share's payer setting (the owner by default); gateway egress always bills the owner.","type":"boolean"}},"required":["id","domain","state","ipns_name_id","pin_count","last_error","dnslink_hint","verified_at","created_at","updated_at"],"additionalProperties":false}},"required":["domain"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Gateway domain detail","description":"One gateway domain with its verification/cert state. Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Domain now deleting","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean"}},"required":["deleted"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Detach a gateway domain","description":"Drops the domain's gateway vhost on the node's next poll. A linked domain (`ipns_name_id`) also best-effort removes the DNS records that were created for it (hand-made records are left alone). Free; idempotent while deleting.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/domains/{id}/pins":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"1–100, default 100"},{"in":"query","name":"offset","required":false,"schema":{"type":"integer"},"description":"Rows to skip, default 0"}],"responses":{"200":{"description":"Attached pins page","content":{"application/json":{"schema":{"type":"object","properties":{"pins":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"cid":{"oneOf":[{"type":"string"},{"type":"null"}]},"cid_v1":{"description":"The CID's base32 CIDv1 spelling — both spellings are allowlisted on the domain.","oneOf":[{"type":"string"},{"type":"null"}]},"name":{"oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string"},"attached_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","cid","cid_v1","name","state","attached_at"],"additionalProperties":false}},"total":{"description":"Attachment count across all pages","type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"}},"required":["pins","total","limit","offset"],"additionalProperties":false}}}},"400":{"description":"Invalid limit or offset","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"List a domain's served pins","description":"The pins the gateway domain serves at `/ipfs/<cid>`, oldest attachment first, server-side paged (`total` is the full count — attachments are unbounded). Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"add":{"type":"array","items":{"type":"string"}},"remove":{"type":"array","items":{"type":"string"}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Domain with its new pin_count","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"ipns_name_id":{"description":"Set when the domain is linked to one of your IPNS names — its DNS records (A + `_dnslink` TXT) are then created and maintained for you.","oneOf":[{"type":"string"},{"type":"null"}]},"pin_count":{"description":"Live pins the domain serves at `/ipfs/<cid>` (unbounded — the pins themselves ride the paged `GET /ipfs/domains/{id}/pins`).","type":"integer"},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"dnslink_hint":{"description":"The TXT record to create on your ird-hosted zone (`ird dns set-record` or the DNS panel). Ignore it on linked rows (`ipns_name_id` set) — the record is managed for you.","type":"string"},"dns_target":{"description":"The gateway node's IPv4 the domain's A record must point at — present on the create response (manual-mapping rows need it to set the A record; linked/pins rows get the record created for them). Any AAAA record at the hostname must be removed (on ird-managed rows it is removed for you): the gateway serves IPv4 only and certificate validation prefers IPv6.","type":"string"},"verified_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"delegated":{"description":"Present (true) in the list on a gateway domain under a domain another account shared with this one through an ipfs grant: manageable here, billed per the share's payer setting (the owner by default); gateway egress always bills the owner.","type":"boolean"}},"required":["id","domain","state","ipns_name_id","pin_count","last_error","dnslink_hint","verified_at","created_at","updated_at"],"additionalProperties":false}},"required":["domain"],"additionalProperties":false}}}},"400":{"description":"A pin is not yours, not live, or has no CID yet","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"The domain's node has no capacity for the replicated content — retry later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Attach or detach served pins","description":"Idempotent attach/detach delta over the domain's served pins — both lists are unbounded, re-adding attached pins and removing absent ones are no-ops, so any number of pins is manageable without ever sending the full set. `add` ids must be your own live CID-bearing pins — they may live on any ird node (content on another node replicates to the domain's node automatically; 503 `capacity-unavailable` when it has no room); `remove` always works. The domain then serves exactly the attached pins at `/ipfs/<cid>` — and only their traffic bills your account.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/ipfs/usage":{"get":{"responses":{"200":{"description":"Usage summary","content":{"application/json":{"schema":{"type":"object","properties":{"usage":{"type":"object","properties":{"pinned_bytes":{"type":"integer"},"served_bytes_period":{"description":"Gateway egress accumulated in the current billing period.","type":"integer"},"per_mb_hour":{"type":"string"},"per_mb_served":{"type":"string"},"hourly_cost":{"type":"string"},"monthly_estimate":{"type":"string"}},"required":["pinned_bytes","served_bytes_period","per_mb_hour","per_mb_served","hourly_cost","monthly_estimate"],"additionalProperties":false}},"required":["usage"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Storage usage and cost","description":"Pinned bytes (distinct CIDs — duplicates of one CID never double-bill), gateway egress accumulated this billing period, the active `recurring.ipfs-pin-hourly` rates, and the cost projection (hourly, and a ×730 monthly estimate). Money values are exact decimal strings. Charged `ipfs.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/apps":{"get":{"responses":{"200":{"description":"Apps","content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hostname":{"description":"The default public hostname, `<name>.ap2p.ro`.","type":"string"},"signaling_url":{"description":"The WebSocket signaling relay (`wss://<hostname>/ws`).","type":"string"},"turn_credentials_url":{"description":"Node-local TURN credential mint (`https://<hostname>/turn-credentials`), origin-checked against the app's allowlist.","type":"string"},"ice_urls":{"type":"array","items":{"type":"string"}},"relay_enabled":{"description":"Whether the app's libp2p circuit-relay-v2 host is on (default true; relayed bytes bill at `per_mb_relayed`).","type":"boolean"},"relay_peer_id":{"description":"The relay's libp2p peer id (`12D3Koo...`), derived on the node from the app's stable identity — null until the node's first report.","oneOf":[{"type":"string"},{"type":"null"}]},"relay_multiaddrs":{"description":"Dialable relay multiaddrs (`/dns4/<host>/tcp/443/tls/ws/p2p/<peer-id>`) for the default hostname and each active non-wildcard custom domain; empty until the peer id is reported or while the relay is disabled. Browser peers listen on `<multiaddr>/p2p-circuit`.","type":"array","items":{"type":"string"}},"mailbox_enabled":{"description":"Whether the app's offline mailbox is on (default false). Peers deposit end-to-end encrypted payloads for rooms and replay them on reconnect; cached bytes bill at `per_mb_hour_cached` and deposits/replays at `per_mb_served_mailbox`.","type":"boolean"},"mailbox_open_mint":{"description":"Whether end-user peers may mint mailbox tokens straight from the node (origin-checked, default true). Turn it off to mint only through POST /p2p/apps/{id}/mailbox-credentials from your own backend — the only option for non-browser peers, which send no Origin header.","type":"boolean"},"mailbox_url":{"description":"Base URL of the app's mailbox API (`https://<hostname>/mailbox/v1`); null while the mailbox is off or the node has not acked the app yet.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"origins":{"description":"WebSocket origin allowlist (exact origins or `*.domain.tld` wildcards); empty = any origin.","type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":{"type":"integer"}},"node":{"oneOf":[{"type":"object","properties":{"hostname":{"type":"string"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["hostname","ipv4"],"additionalProperties":false},{"type":"null"}]},"domains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","hostname","signaling_url","turn_credentials_url","ice_urls","relay_enabled","relay_peer_id","relay_multiaddrs","mailbox_enabled","mailbox_open_mint","mailbox_url","state","origins","settings","node","domains","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}}},"required":["apps"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"List your p2p apps","description":"Every non-deleted p2p app on the account, custom domains embedded. Charged `p2p.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":{"type":"integer"}},"mailbox_enabled":{"type":"boolean"}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"App created (first hour charged)","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hostname":{"description":"The default public hostname, `<name>.ap2p.ro`.","type":"string"},"signaling_url":{"description":"The WebSocket signaling relay (`wss://<hostname>/ws`).","type":"string"},"turn_credentials_url":{"description":"Node-local TURN credential mint (`https://<hostname>/turn-credentials`), origin-checked against the app's allowlist.","type":"string"},"ice_urls":{"type":"array","items":{"type":"string"}},"relay_enabled":{"description":"Whether the app's libp2p circuit-relay-v2 host is on (default true; relayed bytes bill at `per_mb_relayed`).","type":"boolean"},"relay_peer_id":{"description":"The relay's libp2p peer id (`12D3Koo...`), derived on the node from the app's stable identity — null until the node's first report.","oneOf":[{"type":"string"},{"type":"null"}]},"relay_multiaddrs":{"description":"Dialable relay multiaddrs (`/dns4/<host>/tcp/443/tls/ws/p2p/<peer-id>`) for the default hostname and each active non-wildcard custom domain; empty until the peer id is reported or while the relay is disabled. Browser peers listen on `<multiaddr>/p2p-circuit`.","type":"array","items":{"type":"string"}},"mailbox_enabled":{"description":"Whether the app's offline mailbox is on (default false). Peers deposit end-to-end encrypted payloads for rooms and replay them on reconnect; cached bytes bill at `per_mb_hour_cached` and deposits/replays at `per_mb_served_mailbox`.","type":"boolean"},"mailbox_open_mint":{"description":"Whether end-user peers may mint mailbox tokens straight from the node (origin-checked, default true). Turn it off to mint only through POST /p2p/apps/{id}/mailbox-credentials from your own backend — the only option for non-browser peers, which send no Origin header.","type":"boolean"},"mailbox_url":{"description":"Base URL of the app's mailbox API (`https://<hostname>/mailbox/v1`); null while the mailbox is off or the node has not acked the app yet.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"origins":{"description":"WebSocket origin allowlist (exact origins or `*.domain.tld` wildcards); empty = any origin.","type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":{"type":"integer"}},"node":{"oneOf":[{"type":"object","properties":{"hostname":{"type":"string"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["hostname","ipv4"],"additionalProperties":false},{"type":"null"}]},"domains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","hostname","signaling_url","turn_credentials_url","ice_urls","relay_enabled","relay_peer_id","relay_multiaddrs","mailbox_enabled","mailbox_open_mint","mailbox_url","state","origins","settings","node","domains","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["app"],"additionalProperties":false}}}},"400":{"description":"Invalid name, origins or settings; app limit reached; or pricing not configured","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"An app with this name already exists","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"P2P capacity is temporarily full","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Create a p2p app","description":"Provisions a managed WebSocket signaling relay + STUN/TURN + libp2p circuit-relay-v2 at `<name>.ap2p.ro`: a node is assigned, the first prepaid hour is charged (`recurring.p2p-app-hourly` — billing continues hourly at `per_hour` plus `per_mb_relayed` per MiB of relayed traffic (TURN and libp2p circuit relay alike), into a negative balance if needed, until you delete the app), and the DNS record is created automatically. `name` is a public hostname label ([a-z0-9-], 1-63 chars, unique across all accounts; `www|api|signal|stun|turn|admin` and `p<number>` are reserved). `origins` limits which websites may use the relay and mint TURN credentials (exact origins or `*.domain.tld` wildcards; empty = any origin). Signaling traffic is metered but free at launch. The libp2p relay (for js-libp2p/OrbitDB browser peers) announces itself at `relay_multiaddrs` once the node reports the app's peer id. Pass `mailbox_enabled: true` to switch on the offline mailbox, which caches end-to-end encrypted payloads for peers that are not online at the same time (billed per MiB-hour cached at `per_mb_hour_cached`); it is off by default.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/apps/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"App","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hostname":{"description":"The default public hostname, `<name>.ap2p.ro`.","type":"string"},"signaling_url":{"description":"The WebSocket signaling relay (`wss://<hostname>/ws`).","type":"string"},"turn_credentials_url":{"description":"Node-local TURN credential mint (`https://<hostname>/turn-credentials`), origin-checked against the app's allowlist.","type":"string"},"ice_urls":{"type":"array","items":{"type":"string"}},"relay_enabled":{"description":"Whether the app's libp2p circuit-relay-v2 host is on (default true; relayed bytes bill at `per_mb_relayed`).","type":"boolean"},"relay_peer_id":{"description":"The relay's libp2p peer id (`12D3Koo...`), derived on the node from the app's stable identity — null until the node's first report.","oneOf":[{"type":"string"},{"type":"null"}]},"relay_multiaddrs":{"description":"Dialable relay multiaddrs (`/dns4/<host>/tcp/443/tls/ws/p2p/<peer-id>`) for the default hostname and each active non-wildcard custom domain; empty until the peer id is reported or while the relay is disabled. Browser peers listen on `<multiaddr>/p2p-circuit`.","type":"array","items":{"type":"string"}},"mailbox_enabled":{"description":"Whether the app's offline mailbox is on (default false). Peers deposit end-to-end encrypted payloads for rooms and replay them on reconnect; cached bytes bill at `per_mb_hour_cached` and deposits/replays at `per_mb_served_mailbox`.","type":"boolean"},"mailbox_open_mint":{"description":"Whether end-user peers may mint mailbox tokens straight from the node (origin-checked, default true). Turn it off to mint only through POST /p2p/apps/{id}/mailbox-credentials from your own backend — the only option for non-browser peers, which send no Origin header.","type":"boolean"},"mailbox_url":{"description":"Base URL of the app's mailbox API (`https://<hostname>/mailbox/v1`); null while the mailbox is off or the node has not acked the app yet.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"origins":{"description":"WebSocket origin allowlist (exact origins or `*.domain.tld` wildcards); empty = any origin.","type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":{"type":"integer"}},"node":{"oneOf":[{"type":"object","properties":{"hostname":{"type":"string"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["hostname","ipv4"],"additionalProperties":false},{"type":"null"}]},"domains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","hostname","signaling_url","turn_credentials_url","ice_urls","relay_enabled","relay_peer_id","relay_multiaddrs","mailbox_enabled","mailbox_open_mint","mailbox_url","state","origins","settings","node","domains","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["app"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"P2P app detail","description":"One app with its connection URLs, node and custom domains. Charged `p2p.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"App now deleting","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hostname":{"description":"The default public hostname, `<name>.ap2p.ro`.","type":"string"},"signaling_url":{"description":"The WebSocket signaling relay (`wss://<hostname>/ws`).","type":"string"},"turn_credentials_url":{"description":"Node-local TURN credential mint (`https://<hostname>/turn-credentials`), origin-checked against the app's allowlist.","type":"string"},"ice_urls":{"type":"array","items":{"type":"string"}},"relay_enabled":{"description":"Whether the app's libp2p circuit-relay-v2 host is on (default true; relayed bytes bill at `per_mb_relayed`).","type":"boolean"},"relay_peer_id":{"description":"The relay's libp2p peer id (`12D3Koo...`), derived on the node from the app's stable identity — null until the node's first report.","oneOf":[{"type":"string"},{"type":"null"}]},"relay_multiaddrs":{"description":"Dialable relay multiaddrs (`/dns4/<host>/tcp/443/tls/ws/p2p/<peer-id>`) for the default hostname and each active non-wildcard custom domain; empty until the peer id is reported or while the relay is disabled. Browser peers listen on `<multiaddr>/p2p-circuit`.","type":"array","items":{"type":"string"}},"mailbox_enabled":{"description":"Whether the app's offline mailbox is on (default false). Peers deposit end-to-end encrypted payloads for rooms and replay them on reconnect; cached bytes bill at `per_mb_hour_cached` and deposits/replays at `per_mb_served_mailbox`.","type":"boolean"},"mailbox_open_mint":{"description":"Whether end-user peers may mint mailbox tokens straight from the node (origin-checked, default true). Turn it off to mint only through POST /p2p/apps/{id}/mailbox-credentials from your own backend — the only option for non-browser peers, which send no Origin header.","type":"boolean"},"mailbox_url":{"description":"Base URL of the app's mailbox API (`https://<hostname>/mailbox/v1`); null while the mailbox is off or the node has not acked the app yet.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"origins":{"description":"WebSocket origin allowlist (exact origins or `*.domain.tld` wildcards); empty = any origin.","type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":{"type":"integer"}},"node":{"oneOf":[{"type":"object","properties":{"hostname":{"type":"string"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["hostname","ipv4"],"additionalProperties":false},{"type":"null"}]},"domains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","hostname","signaling_url","turn_credentials_url","ice_urls","relay_enabled","relay_peer_id","relay_multiaddrs","mailbox_enabled","mailbox_open_mint","mailbox_url","state","origins","settings","node","domains","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["app"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Delete a p2p app","description":"Stops billing immediately and tears the app (and its custom domains) down on the node's next poll. Free — a negative balance never blocks stopping the app that is billing you. Idempotent while deletion is in progress.","security":[{"apiKey":[]},{"accountJwt":[]}]},"patch":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"origins":{"type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":{"type":"integer"}},"relay_enabled":{"type":"boolean"},"mailbox_enabled":{"type":"boolean"},"mailbox_open_mint":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"App with the new configuration","content":{"application/json":{"schema":{"type":"object","properties":{"app":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"hostname":{"description":"The default public hostname, `<name>.ap2p.ro`.","type":"string"},"signaling_url":{"description":"The WebSocket signaling relay (`wss://<hostname>/ws`).","type":"string"},"turn_credentials_url":{"description":"Node-local TURN credential mint (`https://<hostname>/turn-credentials`), origin-checked against the app's allowlist.","type":"string"},"ice_urls":{"type":"array","items":{"type":"string"}},"relay_enabled":{"description":"Whether the app's libp2p circuit-relay-v2 host is on (default true; relayed bytes bill at `per_mb_relayed`).","type":"boolean"},"relay_peer_id":{"description":"The relay's libp2p peer id (`12D3Koo...`), derived on the node from the app's stable identity — null until the node's first report.","oneOf":[{"type":"string"},{"type":"null"}]},"relay_multiaddrs":{"description":"Dialable relay multiaddrs (`/dns4/<host>/tcp/443/tls/ws/p2p/<peer-id>`) for the default hostname and each active non-wildcard custom domain; empty until the peer id is reported or while the relay is disabled. Browser peers listen on `<multiaddr>/p2p-circuit`.","type":"array","items":{"type":"string"}},"mailbox_enabled":{"description":"Whether the app's offline mailbox is on (default false). Peers deposit end-to-end encrypted payloads for rooms and replay them on reconnect; cached bytes bill at `per_mb_hour_cached` and deposits/replays at `per_mb_served_mailbox`.","type":"boolean"},"mailbox_open_mint":{"description":"Whether end-user peers may mint mailbox tokens straight from the node (origin-checked, default true). Turn it off to mint only through POST /p2p/apps/{id}/mailbox-credentials from your own backend — the only option for non-browser peers, which send no Origin header.","type":"boolean"},"mailbox_url":{"description":"Base URL of the app's mailbox API (`https://<hostname>/mailbox/v1`); null while the mailbox is off or the node has not acked the app yet.","oneOf":[{"type":"string"},{"type":"null"}]},"state":{"type":"string","enum":["pending","active","failed","deleting"]},"origins":{"description":"WebSocket origin allowlist (exact origins or `*.domain.tld` wildcards); empty = any origin.","type":"array","items":{"type":"string"}},"settings":{"type":"object","additionalProperties":{"type":"integer"}},"node":{"oneOf":[{"type":"object","properties":{"hostname":{"type":"string"},"ipv4":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["hostname","ipv4"],"additionalProperties":false},{"type":"null"}]},"domains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"subscription_id":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"updated_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","hostname","signaling_url","turn_credentials_url","ice_urls","relay_enabled","relay_peer_id","relay_multiaddrs","mailbox_enabled","mailbox_open_mint","mailbox_url","state","origins","settings","node","domains","last_error","subscription_id","created_at","updated_at"],"additionalProperties":false}},"required":["app"],"additionalProperties":false}}}},"400":{"description":"Invalid origins or settings, or nothing to update","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The app is being deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Update app origins/settings/relay/mailbox","description":"Replaces the app's origin allowlist and/or limit settings — each provided key is a full replace (send `origins: []` to allow any origin again; omit a key to leave it untouched) — and/or flips the libp2p circuit relay with `relay_enabled`. Settings keys: `max_rooms`, `max_room_peers`, `max_conns_per_ip` (positive integers, clamped at 100000), `max_bytes_per_sec` (per-connection signaling byte budget, default 262144 = 256 KiB/s, clamped at 16777216), `messages_per_sec` (per-connection signaling message rate; stored as a positive integer, sanity-capped at 100000; inherits the node's `signal_messages_per_sec` — built-in 30 — when unset; the effective rate is min(override, the node's `signal_messages_per_sec`), enforced by the node), `message_burst` (per-connection burst; stored as a positive integer, sanity-capped at 100000; inherits the node's `signal_message_burst` — built-in 2× the rate — when unset; the effective burst is min(override, the node's `signal_message_burst`), enforced by the node), `max_relay_reservations` (default 128), `max_relay_circuits` (default 64), `relay_circuit_duration_sec` (default 3600), `relay_circuit_data_mb` (default 512), `max_relay_bytes_per_sec` (default 262144, clamped at 16777216), `max_relay_conns_per_ip` (default 20), `mailbox_ttl_hours` (offline-cache retention, default 24, clamped at 2160), `mailbox_max_mb` (per-app cache ring buffer, default 256, clamped at 10240), `mailbox_max_message_kb` (per-deposit size cap, default 64, clamped at 10240), `mailbox_mint_ip_per_min` (open-mint token budget per client IP per minute, default 10), `mailbox_mint_app_per_min` (open-mint budget per app per minute, default 600). `mailbox_enabled` turns the offline mailbox on or off and `mailbox_open_mint` chooses whether peers may mint mailbox tokens at the node or only through your backend. The node picks the change up within one poll. Charged `p2p.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/apps/{id}/turn-credentials":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"ttl_sec":{"type":"integer"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Credentials","content":{"application/json":{"schema":{"type":"object","properties":{"credentials":{"type":"object","properties":{"username":{"description":"`<unix_expiry>:<app_id>` — coturn's REST credential convention.","type":"string"},"credential":{"type":"string"},"ttl":{"type":"integer"},"urls":{"type":"array","items":{"type":"string"}}},"required":["username","credential","ttl","urls"],"additionalProperties":false}},"required":["credentials"],"additionalProperties":false}}}},"400":{"description":"Invalid ttl_sec","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The app is being deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Mint TURN credentials","description":"Mints short-lived TURN credentials for the app (coturn REST convention: username `<unix_expiry>:<app_id>`, HMAC-SHA1 credential) plus the node's ICE server URLs. `ttl_sec` defaults to 3600 and is capped at 86400. Charged `p2p.credentials` per request; the relayed traffic itself bills `per_mb_relayed` on the app's hourly subscription. Browser clients already talking to the signaling host can also GET `https://<hostname>/turn-credentials` directly (origin-checked, uncharged).","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/apps/{id}/mailbox-credentials":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"room":{"type":"string"},"ttl_sec":{"type":"integer"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Token","content":{"application/json":{"schema":{"type":"object","properties":{"credentials":{"type":"object","properties":{"token":{"description":"Bearer token for the mailbox API: `<unix_expiry>:<app_id>:<nonce>:<base64url room>.<HMAC-SHA1>`. Send it as `Authorization: Bearer <token>`.","type":"string"},"ttl":{"type":"integer"},"expires_at":{"description":"Unix seconds at which the token stops being accepted.","type":"integer"},"endpoint":{"description":"Base URL to call with this token (`https://<hostname>/mailbox/v1`).","type":"string"},"room":{"description":"Present when the token is scoped to a single room; absent for an app-scoped token.","type":"string"}},"required":["token","ttl","expires_at","endpoint"],"additionalProperties":false}},"required":["credentials"],"additionalProperties":false}}}},"400":{"description":"Invalid ttl_sec or room, or the mailbox is not enabled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The app is being deleted","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Mint a mailbox token","description":"Mints a short-lived bearer token for the app's offline mailbox (HMAC-SHA1 over the node secret, the same derivation as TURN). Omit `room` for a token valid in every room, or pass one to scope the token to it — an OrbitDB database address, a gossipsub topic, whatever the app already uses as a rendezvous id. `ttl_sec` defaults to 3600 and is capped at 86400. Requires `mailbox_enabled`. Use this path when `mailbox_open_mint` is off, and for non-browser peers (Node/Go), which cannot use the node's origin-checked mint. Charged `p2p.credentials` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/apps/{id}/domains":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domains","content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}}},"required":["domains"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"List an app's custom domains","description":"The app's non-deleted custom domains. Charged `p2p.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"hostname":{"type":"string"},"wildcard":{"type":"boolean"}},"required":["hostname"],"additionalProperties":false}}}},"responses":{"201":{"description":"Domain attached","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"required":["domain"],"additionalProperties":false}}}},"400":{"description":"Invalid hostname; domain limit reached; wildcard on a zone not hosted on your ird DNS; or a host of the p2p service itself","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Profile incomplete, or registrant verification required for an ird-registered domain","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The hostname is already attached to a p2p app, a tunnel or an app deployment","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Attach a custom domain","description":"Attaches your own hostname to the app on top of the default `<name>.ap2p.ro`. On a zone you host on ird DNS the record is written for you (CNAME to the node — A at the apex) and provisioning starts immediately; on any other zone point a CNAME at `dns_cname_target` and call verify-dns. `wildcard: true` (or a literal `*.` prefix) attaches `*.hostname` — ird-hosted zones only, the certificate rides DNS-01. ird-registered domains must pass registrant verification. Charged `p2p.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/apps/{id}/domains/{domain-id}":{"delete":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"domain-id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Domain now deleting","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"required":["domain"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Detach a custom domain","description":"Detaches the domain — the node drops its vhost on the next poll and the auto-created DNS record on your ird-hosted zone is removed. Free; idempotent while deletion is in progress.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/apps/{id}/domains/{domain-id}/verify-dns":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}},{"in":"path","name":"domain-id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Check result on the domain","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"object","properties":{"id":{"type":"string"},"hostname":{"type":"string"},"wildcard":{"type":"boolean"},"state":{"type":"string","enum":["pending-dns","provisioning","active","failed","deleting"]},"dns_ok":{"oneOf":[{"type":"boolean"},{"type":"null"}]},"dns_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"cert_status":{"type":"string","enum":["pending","issued","failed"]},"dns_cname_target":{"description":"Point a CNAME here (the app's node hostname) for foreign-zone domains.","oneOf":[{"type":"string"},{"type":"null"}]},"last_error":{"oneOf":[{"type":"string"},{"type":"null"}]},"created_at":{"oneOf":[{"type":"string"},{"type":"null"}]}},"required":["id","hostname","wildcard","state","dns_ok","dns_error","cert_status","dns_cname_target","last_error","created_at"],"additionalProperties":false}},"required":["domain"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"Re-check a domain's DNS","description":"Re-verifies that the hostname resolves to the app's node (run it after fixing your records — a pass also retries a failed certificate; wildcards verify through a probe label). Charged `p2p.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/p2p/usage":{"get":{"responses":{"200":{"description":"Usage summary","content":{"application/json":{"schema":{"type":"object","properties":{"usage":{"type":"object","properties":{"apps":{"type":"integer"},"relayed_bytes_period":{"description":"Relayed traffic (TURN + libp2p circuit relay) accumulated in the current billing period (not yet billed; bills at `per_mb_relayed`).","type":"integer"},"mailbox_served_bytes_period":{"description":"Mailbox egress (deposits and replays served) accumulated in the current billing period (not yet billed; bills at `per_mb_served_mailbox`).","type":"integer"},"signal_bytes_total":{"description":"Total signaling bytes observed for your apps — all-time meter, free at launch.","type":"integer"},"signal_bytes_period":{"description":"Deprecated alias of signal_bytes_total (the meter was first shipped under a _period name it never had — same all-time value).","type":"integer"},"relay_bytes_total":{"description":"Total libp2p circuit-relay bytes observed for your apps (all-time meter; the billable period accumulation is in relayed_bytes_period).","type":"integer"},"mailbox_bytes_total":{"description":"Total mailbox deposit/replay bytes observed for your apps (all-time meter; the billable period accumulation is in mailbox_served_bytes_period).","type":"integer"},"cached_bytes":{"description":"Mailbox bytes cached on the nodes right now. A level, not an accumulation: it is what you are being billed per MiB-hour to hold, and it falls as messages expire.","type":"integer"},"per_hour":{"type":"string"},"per_mb_relayed":{"type":"string"},"per_mb_served_mailbox":{"type":"string"},"per_mb_hour_cached":{"type":"string"},"hourly_cost":{"description":"What your apps buy per hour right now: the sum over every still-billing app of `per_hour` plus `per_mb_hour_cached` × its cached mailbox MiB. Apps being deleted are left out; relayed and mailbox-served traffic bill as they land and are not included.","type":"string"},"monthly_estimate":{"description":"`hourly_cost` × 730 — the flat hours and mailbox storage alone, traffic excluded.","type":"string"}},"required":["apps","relayed_bytes_period","mailbox_served_bytes_period","signal_bytes_total","signal_bytes_period","relay_bytes_total","mailbox_bytes_total","cached_bytes","per_hour","per_mb_relayed","per_mb_served_mailbox","per_mb_hour_cached","hourly_cost","monthly_estimate"],"additionalProperties":false}},"required":["usage"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Complete customer profile (personal details, verified phone, billing profile) required","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["p2p"],"summary":"P2P usage and cost","description":"Live app count, relayed bytes (TURN + libp2p circuit relay) and mailbox-served bytes accumulated this billing period (billed `per_mb_relayed` and `per_mb_served_mailbox` at the next hourly settle), total signaling bytes observed (metered, free at launch), the active `recurring.p2p-app-hourly` rates and the cost projection (hourly = `per_hour` × apps, and a ×730 monthly estimate). Money values are exact decimal strings. Charged `p2p.reads` per request.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/pins":{"get":{"parameters":[{"in":"query","name":"cid","required":false,"schema":{"type":"string"},"description":"Comma-separated, at most 10"},{"in":"query","name":"name","required":false,"schema":{"type":"string"}},{"in":"query","name":"match","required":false,"schema":{"type":"string","enum":["exact","iexact","partial","ipartial"]}},{"in":"query","name":"status","required":false,"schema":{"type":"string"},"description":"Comma-separated of queued|pinning|pinned|failed; absent = pinned only"},{"in":"query","name":"before","required":false,"schema":{"type":"string"}},{"in":"query","name":"after","required":false,"schema":{"type":"string"}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer"},"description":"1–1000, default 10"}],"responses":{"200":{"description":"PinResults","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer"},"results":{"type":"array","items":{"type":"object","properties":{"requestid":{"type":"string"},"status":{"type":"string","enum":["queued","pinning","pinned","failed"]},"created":{"type":"string"},"pin":{"type":"object","properties":{"cid":{"type":"string"},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","additionalProperties":{"type":"string"}}},"required":["cid"],"additionalProperties":false},"delegates":{"type":"array","items":{"type":"string"}},"info":{"type":"object","additionalProperties":{"type":"string"}}},"required":["requestid","status","created","pin","delegates","info"],"additionalProperties":false}}},"required":["count","results"],"additionalProperties":false}}}},"400":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"List pin objects (Pinning Service API)","description":"Standard [IPFS Pinning Service API 1.0.0](https://ipfs.github.io/pinning-services-api-spec/) listing. Defaults to `status=pinned` when no status filter is given (spec behavior); `count` is the total match count regardless of `limit`. The `cid` filter matches either spelling of a CID (the one you pinned or its canonical CIDv1 form). Charged `ipfs.reads` per request. Add the service to kubo with `ipfs pin remote service add ird https://api.ird.ro ird_…`.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cid":{"type":"string"},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","additionalProperties":{"type":"string"}}},"required":["cid"],"additionalProperties":false}}}},"responses":{"202":{"description":"PinStatus","content":{"application/json":{"schema":{"type":"object","properties":{"requestid":{"type":"string"},"status":{"type":"string","enum":["queued","pinning","pinned","failed"]},"created":{"type":"string"},"pin":{"type":"object","properties":{"cid":{"type":"string"},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","additionalProperties":{"type":"string"}}},"required":["cid"],"additionalProperties":false},"delegates":{"type":"array","items":{"type":"string"}},"info":{"type":"object","additionalProperties":{"type":"string"}}},"required":["requestid","status","created","pin","delegates","info"],"additionalProperties":false}}}},"400":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"INSUFFICIENT_FUNDS — top up at https://ird.ro/panel","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Add a pin (Pinning Service API)","description":"Standard Pinning Service API pin-add: `202` with a PinStatus whose `requestid` you poll. Billing and funding rules are the native surface's (`recurring.ipfs-pin-hourly`); insufficient credits answer `409 INSUFFICIENT_FUNDS` per the spec.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/pins/{requestid}":{"get":{"parameters":[{"in":"path","name":"requestid","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"PinStatus","content":{"application/json":{"schema":{"type":"object","properties":{"requestid":{"type":"string"},"status":{"type":"string","enum":["queued","pinning","pinned","failed"]},"created":{"type":"string"},"pin":{"type":"object","properties":{"cid":{"type":"string"},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","additionalProperties":{"type":"string"}}},"required":["cid"],"additionalProperties":false},"delegates":{"type":"array","items":{"type":"string"}},"info":{"type":"object","additionalProperties":{"type":"string"}}},"required":["requestid","status","created","pin","delegates","info"],"additionalProperties":false}}}},"401":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Pin object (Pinning Service API)","description":"One PinStatus by requestid; foreign or deleted pins are 404.","security":[{"apiKey":[]},{"accountJwt":[]}]},"post":{"parameters":[{"in":"path","name":"requestid","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"cid":{"type":"string"},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","additionalProperties":{"type":"string"}}},"required":["cid"],"additionalProperties":false}}}},"responses":{"202":{"description":"PinStatus (new requestid)","content":{"application/json":{"schema":{"type":"object","properties":{"requestid":{"type":"string"},"status":{"type":"string","enum":["queued","pinning","pinned","failed"]},"created":{"type":"string"},"pin":{"type":"object","properties":{"cid":{"type":"string"},"name":{"type":"string"},"origins":{"type":"array","items":{"type":"string"}},"meta":{"type":"object","additionalProperties":{"type":"string"}}},"required":["cid"],"additionalProperties":false},"delegates":{"type":"array","items":{"type":"string"}},"info":{"type":"object","additionalProperties":{"type":"string"}}},"required":["requestid","status","created","pin","delegates","info"],"additionalProperties":false}}}},"400":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"INSUFFICIENT_FUNDS","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Replace a pin (Pinning Service API)","description":"Replaces the pinned object: the new pin inserts first (shared blocks stay referenced on the node), then the old one starts deleting. `202` with the NEW requestid.","security":[{"apiKey":[]},{"accountJwt":[]}]},"delete":{"parameters":[{"in":"path","name":"requestid","required":true,"schema":{"type":"string"}}],"responses":{"202":{"description":"Accepted, no body"},"401":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Error (spec Failure shape)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"reason":{"type":"string"},"details":{"type":"string"}},"required":["reason"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["ipfs"],"summary":"Remove a pin (Pinning Service API)","description":"Stops billing immediately and unpins on the node's next poll. `202` with no body per the spec.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/jobs":{"post":{"requestBody":{"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"domains":{"type":"array","items":{"type":"string","minLength":3,"maxLength":255},"minItems":1,"maxItems":100},"type":{"const":"domain-availability-bulk"}},"required":["domains","type"],"additionalProperties":false},{"type":"object","properties":{"input":{"type":"string","minLength":1},"model":{"type":"string","enum":["BAAI/bge-m3"]},"type":{"const":"embedding"}},"required":["input","type"],"additionalProperties":false},{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object","properties":{"role":{"type":"string","enum":["system","user","assistant"]},"content":{"type":"string","minLength":1,"maxLength":1000000}},"required":["role","content"],"additionalProperties":false},"minItems":1,"maxItems":50},"model":{"type":"string","enum":["QuantTrio/Qwen3.6-35B-A3B-AWQ"]},"max_tokens":{"type":"integer","minimum":1,"maximum":8192},"temperature":{"allOf":[{"type":"number"},{"type":"number","minimum":0},{"type":"number","maximum":2}]},"type":{"const":"llm-chat"}},"required":["messages","type"],"additionalProperties":false},{"type":"object","properties":{"prompt":{"type":"string","minLength":1,"maxLength":1000000},"model":{"type":"string","enum":["QuantTrio/Qwen3.6-35B-A3B-AWQ"]},"max_tokens":{"type":"integer","minimum":1,"maximum":8192},"temperature":{"allOf":[{"type":"number"},{"type":"number","minimum":0},{"type":"number","maximum":2}]},"type":{"const":"llm-raw-completion"}},"required":["prompt","type"],"additionalProperties":false},{"type":"object","properties":{"input":{"type":"string","minLength":1,"maxLength":200000},"language":{"type":"string","enum":["auto","en","fr","ro"]},"type":{"const":"nlp-analyze"}},"required":["input","type"],"additionalProperties":false},{"type":"object","properties":{"input":{"type":"string","minLength":1,"maxLength":100000},"type":{"const":"nlp-detect-language"}},"required":["input","type"],"additionalProperties":false}]}}}},"responses":{"202":{"description":"Job accepted and queued","content":{"application/json":{"schema":{"type":"object","properties":{"job":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"status":{"type":"string","enum":["queued"]},"created_at":{"type":"string"}},"required":["id","type","status","created_at"],"additionalProperties":false}},"required":["job"],"additionalProperties":false}}}},"400":{"description":"Unknown job type or invalid payload (includes a details map)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"413":{"description":"Input exceeds the maximum payload size (default 1,000,000 bytes)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"The job type's backend is not configured here (code `capacity-unavailable`) — nothing enqueued; retry later","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["jobs"],"summary":"Enqueue a job","description":"Submits a job for asynchronous processing and returns `202 Accepted` immediately. Poll `GET /jobs/{id}` until the status is terminal, then fetch the result from `GET /jobs/{id}/result`. The body is the job payload plus a `type` field; submitted content is held in Redis only and never persisted. Per-field schema bounds are per-field maxima — the serialized whole payload is additionally capped (413, default 1,000,000 bytes), and that cap is the joint limit across fields.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/jobs/{id}":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job status","content":{"application/json":{"schema":{"type":"object","properties":{"job":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"status":{"type":"string","enum":["queued","processing","succeeded","failed"]},"error":{"oneOf":[{"type":"string"},{"type":"null"}]},"attempts":{"type":"integer"},"created_at":{"type":"string"},"started_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"finished_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"bytes_in":{"oneOf":[{"type":"integer"},{"type":"null"}]},"bytes_out":{"oneOf":[{"type":"integer"},{"type":"null"}]},"duration_ms":{"oneOf":[{"type":"integer"},{"type":"null"}]},"result_expires_at":{"type":"string"}},"required":["id","type","status","error","attempts","created_at","started_at","finished_at","bytes_in","bytes_out","duration_ms"],"additionalProperties":false}},"required":["job"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["jobs"],"summary":"Poll job status","description":"Returns the job's status and usage metrics — never submitted content or results. Terminal statuses are `succeeded` and `failed`; succeeded jobs include `result_expires_at` (24h after completion). A non-null `error` alone is not terminal: a failed attempt keeps its error visible while the job is `queued` or `processing` for a retry (`attempts` counts processing attempts so far) — only `status` signals the outcome.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/jobs/{id}/result":{"get":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Job result (shape depends on the job type: `embedding` jobs return `embedding`/`model`/`usage`/`llm-job-id`; `llm-chat` returns `content`/`model`/`usage`/`finish_reason`/`llm-job-id`; `llm-raw-completion` returns `text`/`model`/`usage`/`llm-job-id`; `nlp-analyze` returns the linguistic analysis (`sentences`, `tokens`, `entities`, ... — minus the echoed input); `nlp-detect-language` returns `language`/`confidence`/`alternatives`; `domain-availability-bulk` returns per-domain `results`)","content":{"application/json":{"schema":{"type":"object","properties":{"job-id":{"type":"string"},"type":{"type":"string"},"result":{"type":"object","additionalProperties":{}}},"required":["job-id","type","result"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Job is not finished yet; the body includes the current status","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false},"status":{"type":"string","enum":["queued","processing","failed"]}},"required":["error","status"],"additionalProperties":false}}}},"410":{"description":"Job succeeded but the result has expired (results are kept for 24 hours)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["jobs"],"summary":"Fetch job result","description":"Returns the result of a succeeded job. Results are held for 24 hours after completion, then expire.","security":[{"apiKey":[]},{"accountJwt":[]}]}},"/grants":{"get":{"responses":{"200":{"description":"Grants","content":{"application/json":{"schema":{"type":"object","properties":{"grants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"registration_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"state":{"type":"string","enum":["pending","active","revoked","declined","left"]},"invited_email":{"type":"string"},"payer":{"description":"Who is billed for usage under the grant — the domain owner (the default), the grantee, or split (each charge booked half to each). Fixed at invite time; resources a delegate creates live on the owner's account in every mode, and IPFS gateway egress bills the owner regardless.","type":"string","enum":["owner","grantee","split"]},"inactive":{"description":"True on a pending/active grant whose registration expired, transferred out or changed owner — it confers nothing until re-granted.","type":"boolean"},"created_at":{"type":"string"},"accepted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string"},"owner_email":{"type":"string"}},"required":["id","registration_id","scopes","state","invited_email","payer","inactive","created_at","accepted_at","revoked_at"],"additionalProperties":false}}},"required":["grants"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["sharing"],"summary":"Domains shared with this account","description":"Active grants where this account is the grantee plus pending invites addressed to any email it controls, newest first, with the domain name and the owner's email joined. Work on shared domains is billed per the share's payer setting (see `payer` — the owner by default). Session JWT only.","security":[{"accountJwt":[]}]}},"/grants/{id}/accept":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Active grant","content":{"application/json":{"schema":{"type":"object","properties":{"grant":{"type":"object","properties":{"id":{"type":"string"},"registration_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"state":{"type":"string","enum":["pending","active","revoked","declined","left"]},"invited_email":{"type":"string"},"payer":{"description":"Who is billed for usage under the grant — the domain owner (the default), the grantee, or split (each charge booked half to each). Fixed at invite time; resources a delegate creates live on the owner's account in every mode, and IPFS gateway egress bills the owner regardless.","type":"string","enum":["owner","grantee","split"]},"inactive":{"description":"True on a pending/active grant whose registration expired, transferred out or changed owner — it confers nothing until re-granted.","type":"boolean"},"created_at":{"type":"string"},"accepted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string"},"owner_email":{"type":"string"}},"required":["id","registration_id","scopes","state","invited_email","payer","inactive","created_at","accepted_at","revoked_at"],"additionalProperties":false}},"required":["grant"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The invite is no longer valid","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["sharing"],"summary":"Accept a delegated-access invite","description":"Activates a pending invite addressed to an email this account controls. The grant's validity is re-proven first (registration live, owner unchanged). Check `payer` before accepting: on a grantee-pays share your work there — including hourly charges for resources you create — bills YOUR credits, and on a split share half of every charge does. Session JWT only.","security":[{"accountJwt":[]}]}},"/grants/{id}/decline":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Declined grant","content":{"application/json":{"schema":{"type":"object","properties":{"grant":{"type":"object","properties":{"id":{"type":"string"},"registration_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"state":{"type":"string","enum":["pending","active","revoked","declined","left"]},"invited_email":{"type":"string"},"payer":{"description":"Who is billed for usage under the grant — the domain owner (the default), the grantee, or split (each charge booked half to each). Fixed at invite time; resources a delegate creates live on the owner's account in every mode, and IPFS gateway egress bills the owner regardless.","type":"string","enum":["owner","grantee","split"]},"inactive":{"description":"True on a pending/active grant whose registration expired, transferred out or changed owner — it confers nothing until re-granted.","type":"boolean"},"created_at":{"type":"string"},"accepted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string"},"owner_email":{"type":"string"}},"required":["id","registration_id","scopes","state","invited_email","payer","inactive","created_at","accepted_at","revoked_at"],"additionalProperties":false}},"required":["grant"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The invite is no longer valid","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["sharing"],"summary":"Decline a delegated-access invite","security":[{"accountJwt":[]}]}},"/grants/{id}/leave":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Left grant","content":{"application/json":{"schema":{"type":"object","properties":{"grant":{"type":"object","properties":{"id":{"type":"string"},"registration_id":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["dns","tunnel","ipfs","vps"]}},"state":{"type":"string","enum":["pending","active","revoked","declined","left"]},"invited_email":{"type":"string"},"payer":{"description":"Who is billed for usage under the grant — the domain owner (the default), the grantee, or split (each charge booked half to each). Fixed at invite time; resources a delegate creates live on the owner's account in every mode, and IPFS gateway egress bills the owner regardless.","type":"string","enum":["owner","grantee","split"]},"inactive":{"description":"True on a pending/active grant whose registration expired, transferred out or changed owner — it confers nothing until re-granted.","type":"boolean"},"created_at":{"type":"string"},"accepted_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"domain":{"type":"string"},"owner_email":{"type":"string"}},"required":["id","registration_id","scopes","state","invited_email","payer","inactive","created_at","accepted_at","revoked_at"],"additionalProperties":false}},"required":["grant"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Per-key rate limit exceeded (default 120 requests/minute)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["sharing"],"summary":"Walk away from an active grant","description":"Ends the caller's own grant. On a grantee-pays or split share this also returns hourly billing for resources the delegation anchored fully to the owner — leaving is the grantee's escape hatch even after the grant lapsed.","security":[{"accountJwt":[]}]}},"/auth/device/start":{"post":{"responses":{"200":{"description":"Device flow opened","content":{"application/json":{"schema":{"type":"object","properties":{"device_code":{"type":"string"},"user_code":{"type":"string"},"verification_uri":{"type":"string"},"verification_uri_complete":{"type":"string"},"expires_in":{"type":"integer"},"interval":{"type":"integer"}},"required":["device_code","user_code","verification_uri","verification_uri_complete","expires_in","interval"],"additionalProperties":false}}}},"429":{"description":"Too many flows started from this address","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["auth"],"summary":"Start a device login","description":"Opens a device-authorization flow (`ird login`). Returns an opaque `device_code` (the polling secret — keep it on the device) and a short `user_code` to display; the user enters the code at `verification_uri` while signed in and approves the device there. Poll `/auth/device/poll` at `interval` seconds until approved, then exchange the browser-shown confirmation code at `/auth/device/complete`. The flow expires after `expires_in` seconds.","security":[{}]}},"/auth/device/poll":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"device_code":{"type":"string"}},"required":["device_code"],"additionalProperties":false}}}},"responses":{"200":{"description":"Approved — ask the user for the confirmation code","content":{"application/json":{"schema":{"type":"object","properties":{"approved":{"type":"boolean"}},"required":["approved"],"additionalProperties":false}}}},"400":{"description":"Still waiting for approval (`authorization-pending`)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Flow expired, unknown, or already consumed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The user denied the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Polling too fast (`slow-down`)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["auth"],"summary":"Poll a device login","description":"Reports the flow state for `device_code`. `400 authorization-pending` while the user hasn't approved yet; `{\"approved\": true}` once approved — then prompt for the confirmation code shown in the user's browser and call `/auth/device/complete`. Respect `429 slow-down` by increasing the polling interval. `403 access-denied` (denied) and `401 session-expired` (expired or consumed) are terminal.","security":[{}]}},"/auth/device/complete":{"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"device_code":{"type":"string"},"confirmation_code":{"type":"string"}},"required":["device_code","confirmation_code"],"additionalProperties":false}}}},"responses":{"200":{"description":"Device session created","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"user":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"created_at":{"type":"string"}},"required":["id","email","created_at"],"additionalProperties":false}},"required":["access_token","refresh_token","user"],"additionalProperties":false}}}},"400":{"description":"Not approved yet (`authorization-pending`)","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Flow expired, unknown, or already consumed","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The user denied the request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"Wrong confirmation code","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["auth"],"summary":"Complete a device login","description":"Exchanges `device_code` plus the confirmation code shown in the user's browser for an access/refresh token pair. Single-use: a second call answers `401`. Five wrong confirmation codes destroy the flow.","security":[{}]}},"/auth/api-keys":{"get":{"responses":{"200":{"description":"API keys","content":{"application/json":{"schema":{"type":"object","properties":{"api-keys":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"key_prefix":{"type":"string"},"created_at":{"type":"string"},"last_used_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","revoked"]}},"required":["id","name","key_prefix","created_at","last_used_at","revoked_at","revoked_reason","status"],"additionalProperties":false}}},"required":["api-keys"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["api-keys"],"summary":"List API keys","description":"Full key history for the authenticated account, newest first. Key material is never returned — only the display prefix.","security":[{"accountJwt":[]}]},"post":{"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"Key created; `token` is shown only in this response","content":{"application/json":{"schema":{"type":"object","properties":{"api-key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"key_prefix":{"type":"string"},"created_at":{"type":"string"},"last_used_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_at":{"oneOf":[{"type":"string"},{"type":"null"}]},"revoked_reason":{"oneOf":[{"type":"string"},{"type":"null"}]},"status":{"type":"string","enum":["active","revoked"]}},"required":["id","name","key_prefix","created_at","last_used_at","revoked_at","revoked_reason","status"],"additionalProperties":false},"token":{"type":"string"}},"required":["api-key","token"],"additionalProperties":false}}}},"400":{"description":"Invalid name or too many active keys","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["api-keys"],"summary":"Create an API key","description":"Creates a key and returns the full token **once** — it is stored only as a hash and cannot be retrieved again. At most 20 active keys per account.","security":[{"accountJwt":[]}]}},"/auth/api-keys/{id}/revoke":{"post":{"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Key revoked","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"}},"required":["ok"],"additionalProperties":false}}}},"401":{"description":"Missing, invalid, or revoked credentials","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Resource not found or owned by another account","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}},"tags":["api-keys"],"summary":"Revoke an API key","description":"Revocation is immediate: requests using the key fail with `401` from the next call. Revoked keys stay in the list as history.","security":[{"accountJwt":[]}]}}}}