{"openapi":"3.1.0","info":{"title":"SatsDNS API","version":"0.3.16","summary":"Sats-paid authoritative DNS hosting, secondary DNS, dynamic DNS and domain registration for agents and people.","description":"SatsDNS: authoritative DNS hosting (DNSSEC-signed, record API), secondary DNS, dynamic-DNS\nhostnames under dynkite.com and .com/.net/.org domain registration, paid in sats per order.\nDocumentation: https://satsdns.com/docs\n\nTwo ways to buy:\n\n1. No account. The paid routes (/v1/zones/create/..., /v1/zones/renew/..., /v1/zones/queries/1m,\n/v1/ddns/create/..., /v1/ddns/renew/..., /v1/secondary/create/...) answer 402 with two ways to\npay: L402 (`WWW-Authenticate: L402 macaroon=\"...\", invoice=\"...\"`, then retry with\n`Authorization: L402 <macaroon>:<preimage>`) or Cashu NUT-24 (`X-Cashu: creqA...`, then retry\nwith `X-Cashu: cashuB...`). Every paid request is checked for free first; a request that would\nfail gets its 4xx and no invoice. A refusal after payment is a 422 (or 503) and comes with\n`X-L402-Retry: allowed` (the same credential works once more) or `X-Cashu-Refund: cashuB...`.\nThe answer carries a management token (jdz_ for zones, jdh_ for hostnames), shown once.\n\n2. A Nostr account (free). Sign requests with NIP-98 and order with POST /v1/account/orders:\neach order gets its own Lightning invoice, or a bitcoin address for orders of at least\n5,000 sats. There is no stored balance and no auto-renew.\n\nDomain registration (.com, .net, .org) is sold through account orders only (products\ndomain_register, domain_renew, domain_transfer), quoted per order in sats, with the named\nregistrant as holder, WHOIS privacy always on, and Global Domain Group LLC (IANA ID 3956) as\nsponsoring registrar, under https://satsdns.com/registration-agreement . Free quote:\nGET /v1/domains/check. Management with the domain token (jdd_...) or the owning account. Abuse\nreports: POST /v1/abuse/reports or abuse@satsdns.com, answered within 5 business days.\n\nManagement routes are not paid per call. They accept the object's token, NIP-98 by the\nowning account, an account API key (jdk_) or a dashboard session (app.satsdns.com only)."},"servers":[{"url":"https://api.satsdns.com","description":"API for agents and scripts"},{"url":"https://app.satsdns.com","description":"Dashboard host: same API, the only host for session cookies"},{"url":"https://pay.satsdns.com","description":"Lightning addresses and LNURL-pay renewals only"}],"tags":[{"name":"paid"},{"name":"zones"},{"name":"records"},{"name":"ddns"},{"name":"free"},{"name":"auth"},{"name":"account"},{"name":"billing"},{"name":"secondary"},{"name":"lnurl"},{"name":"domains"}],"components":{"securitySchemes":{"zoneToken":{"type":"http","scheme":"bearer","description":"Zone management token (jdz_...), shown once at purchase."},"domainToken":{"type":"http","scheme":"bearer","description":"Domain management token (jdd_...), shown once when a registration or transfer is paid. It is owner-equivalent: whoever holds it can change nameservers and DNSSEC, unlock the domain, change the registrant and rotate the token. Keep it as safe as the account key. One exception: when an account owns the domain, the transfer code (POST /v1/domains/{domain}/auth-code) needs the owner's NIP-98 signature, not the token."},"hostToken":{"type":"http","scheme":"bearer","description":"Hostname token (jdh_...), shown once at purchase."},"dyndnsBasic":{"type":"http","scheme":"basic","description":"Any user name; the hostname token as password."},"l402":{"type":"apiKey","in":"header","name":"Authorization","description":"L402 <macaroon>:<preimage> (from the 402 challenge)"},"cashu":{"type":"apiKey","in":"header","name":"X-Cashu","description":"Cashu token (NUT-24) worth the price plus the mint's input fee."},"nip98":{"type":"apiKey","in":"header","name":"Authorization","description":"\"Nostr <base64 kind-27235 event>\". Bound to scheme+host+path+query (u tag, byte for\nbyte), method, and for non-GET/HEAD the sha256 of the raw body (payload tag, required).\n60 s window, each event id usable once.\n\nProof of work (NIP-13) for accounts without a paid order (\"new unpaid\"): at sign-in (POST /v1/auth/session), account orders (also pay \"check\"), signed domain checks and the first action that creates the account, the event must carry one tag [\"nonce\", \"<counter>\", \"<target>\"] with a committed target of at least pow_bits (GET /v1/info accounts.pow_bits; also detail.pow_bits in every Nostr 401), and its id must have at least that many leading zero bits. A lower committed target is refused even when the id happens to meet the requirement. Mine before signing: the id depends only on pubkey, created_at, kind, tags and content. Otherwise 401 pow_required. Accounts with a paid order, sessions, API keys and tokens need none.\n"},"nip98StepUp":{"type":"apiKey","in":"header","name":"Authorization","description":"A fresh NIP-98 event; a session or API key is refused with 401 step_up_required."},"apiKey":{"type":"http","scheme":"bearer","description":"Account API key (jdk_...), scoped."},"session":{"type":"apiKey","in":"cookie","name":"__Host-jdsess","description":"Dashboard session (app host only). Writes also need X-SatsDNS-CSRF and Origin."}},"parameters":{"period":{"name":"period","in":"path","required":true,"schema":{"type":"string","enum":["30d","1y"]}},"zone":{"name":"zone","in":"path","required":true,"schema":{"type":"string","example":"example.com"}},"hostname":{"name":"hostname","in":"path","required":true,"schema":{"type":"string","example":"myhost"}},"id":{"name":"id","in":"path","required":true,"schema":{"type":"string"}},"payId":{"name":"pay_id","in":"path","required":true,"schema":{"type":"string","pattern":"^([a-z2-7]{12}|zaps)$"}},"idempotencyKey":{"name":"Idempotency-Key","in":"header","required":false,"description":"The same key and body within 24 h replay the first answer; the same key with another body is 409 idempotency_conflict; while the first request with the key is still running, 409 idempotency_in_progress (retry shortly). A request that fails frees its key.","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}},"csrf":{"name":"X-SatsDNS-CSRF","in":"header","required":false,"description":"Required with the session cookie on non-GET requests.","schema":{"type":"string"}}},"responses":{"PaymentRequired":{"description":"Pay with L402 or Cashu, then send the same request again with the proof.","headers":{"WWW-Authenticate":{"schema":{"type":"string"}},"X-Cashu":{"schema":{"type":"string"}}}},"Error":{"description":"Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"RateLimited":{"description":"Too many requests. Account calls are counted per npub (npub_limit; detail.rule, limit, period_s, tier) and, for accounts without a paid order, also in one window for those of the caller's network (network_limit) and one shared by all of them (global_limit). Wait Retry-After; a first paid order lifts the new-account limits.","headers":{"Retry-After":{"schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid credentials. For NIP-98 failures also a Date header and detail.server_time. Every Nostr challenge carries detail.pow_bits (proof of work for accounts without a paid order); pow_required also names detail.rule \"pow\", detail.action and detail.tier \"new_unpaid\". The error has a hint (no account is needed to buy, as the paid create routes return the management token; what the route accepts) and a docs link.","headers":{"WWW-Authenticate":{"schema":{"type":"string","example":"Nostr"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NoContent":{"description":"No content"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","examples":["auth_expired","auth_replayed","pow_required","npub_limit","network_limit","global_limit","auth_url_mismatch","step_up_required","csrf_failed","onchain_minimum","limit_reached","bad_primary","zone_is_secondary","idempotency_conflict","idempotency_in_progress","account_has_domains","token_reissue_required","address_not_public","account_frozen","onchain_unavailable","lightning_unavailable","confirmations_pending","amount_out_of_range","invalid_scope","forbidden_scope","account_banned","account_deleted","not_offered","missing_token","invalid_token","ipv6_primary_unsupported","too_many_peers","zone_is_primary","delegation_missing","delegation_mismatch","delegation_check_unavailable","delegation_check_busy","ns_ticket_invalid","ns_offer_limit","ns_offers_exhausted","ns_offers_full","zone_reserved","domain_owner_only","create_timeout"]},"message":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"object"},"retry_after_s":{"type":"integer"},"request_id":{"type":"string","description":"Also in the X-Request-Id header; quote it when asking for help."},"hint":{"type":"string","description":"What to do instead (401 on management and account routes, 405)."},"docs":{"type":"string","description":"Documentation link for the hint."}}}}},"ZoneBody":{"type":"object","required":["zone"],"additionalProperties":false,"properties":{"zone":{"type":"string","description":"ASCII name (IDNs as xn--), delegated to our nameservers"}}},"ZoneCreateBody":{"type":"object","required":["zone"],"additionalProperties":false,"description":"Each zone gets its own pair of nameserver names, <label>.ns1.satsdns.com and <label>.ns2.satsdns.com. Send {\"zone\"} first: the free check answers 409 delegation_missing with detail.expected_ns (the pair to set at your registrar), detail.ns_ticket (shown once) and detail.ns_offer_expires_at (48 hours; 7 days for an account's pair). Once the registry lists the pair, send the request again with ns_ticket; only then is there an invoice. Account orders need no ticket: the pair is bound to the account. A domain its TLD's registry does not know gets no pair: 409 delegation_missing without expected_ns (detail.registered false); register it first, then check again. Limits: 2 open pairs per client address and zone, 20 a day per network (IPv4 /24, IPv6 /48), 50 open per account (429 ns_offer_limit).","properties":{"zone":{"type":"string","description":"ASCII name (IDNs as xn--)"},"ns_ticket":{"type":"string","description":"The secret from the free check's 409 detail.ns_ticket (nst_...)"},"previous_token":{"type":"string","description":"The management token of a zone of this name removed in the last 90 days (or still delegated to its nameservers): only its last owner can host the name again, on the same nameserver names."}}},"HostnameBody":{"type":"object","required":["hostname"],"additionalProperties":false,"properties":{"hostname":{"type":"string","description":"one label, 4-63 characters, a-z 0-9 hyphen"}}},"Limits":{"type":"object","properties":{"max_records":{"type":"integer"},"writes_per_day":{"type":"integer"},"writes_today":{"type":"integer"},"min_ttl":{"type":"integer"},"queries_per_month":{"type":"integer"}}},"Queries":{"type":"object","properties":{"month":{"type":"string"},"counted":{"type":"boolean"},"used":{"type":"integer"},"included":{"type":"integer"},"extra":{"type":"integer"},"remaining":{"type":"integer"},"over_quota":{"type":"boolean"}}},"Dnssec":{"type":"object","properties":{"zone":{"type":"string"},"algorithm":{"type":"string"},"ds":{"type":"array","items":{"type":"string"},"description":"SHA-256 DS: give these to the registrar"},"ds_all_digests":{"type":"array","items":{"type":"string"}},"cds":{"type":"array","items":{"type":"string"}},"cdnskey":{"type":"array","items":{"type":"string"}},"dnskey":{"type":"array","items":{"type":"string"}},"how_to":{"type":"string"}}},"ZoneStatus":{"type":"object","properties":{"zone":{"type":"string"},"status":{"type":"string","enum":["active","grace","expired","suspended"]},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":"string","format":"date-time"},"grace_ends_at":{"type":"string","format":"date-time"},"removal_after":{"type":"string","format":"date-time"},"days_left":{"type":"integer"},"nameservers":{"type":"array","description":"This zone's own nameserver names (the NS records to keep at the registrar)","items":{"type":"string"}},"records":{"type":"integer"},"limits":{"$ref":"#/components/schemas/Limits"},"queries":{"$ref":"#/components/schemas/Queries"},"warning":{"type":"string"},"dnssec":{"$ref":"#/components/schemas/Dnssec"},"token":{"type":"string","description":"only in the create answer"},"token_note":{"type":"string"}}},"RRset":{"type":"object","required":["name","type","records"],"properties":{"name":{"type":"string","description":"@, a relative name, or a full name inside the zone"},"type":{"type":"string","enum":["A","AAAA","CNAME","TXT","MX","SRV","CAA","HTTPS","SVCB","TLSA","NS","DS"]},"ttl":{"type":"integer","minimum":60,"maximum":86400,"default":3600},"records":{"type":"array","items":{"type":"string"},"maxItems":100},"changetype":{"type":"string","enum":["REPLACE","DELETE"],"default":"REPLACE"}}},"ChangeResult":{"type":"object","properties":{"changed":{"type":"array","items":{"type":"object"}},"records":{"type":"integer"},"writes_today":{"type":"integer"},"writes_per_day":{"type":"integer"}}},"HostStatus":{"type":"object","properties":{"hostname":{"type":"string"},"status":{"type":"string","enum":["active","grace","expired","suspended"]},"expires_at":{"type":"string","format":"date-time"},"grace_ends_at":{"type":"string","format":"date-time"},"days_left":{"type":"integer"},"ttl":{"type":"integer"},"updates_today":{"type":"integer"},"updates_per_day":{"type":"integer"},"records":{"type":"object"},"token":{"type":"string"},"token_disabled":{"type":"boolean","description":"Present (true) only when the token is disabled."},"token_retired":{"type":"boolean","description":"Present (true) when the disabled token was retired by a change of owner (transfer or recovery) and not reissued since; enabling it gives 409 token_reissue_required, POST .../token issues a new one."}}},"HostUpdate":{"type":"object","additionalProperties":false,"description":"A value or list replaces, null deletes, an absent field is left alone. a and aaaa take public (globally routed) addresses only; private, loopback, link-local, shared CGNAT, unique-local, multicast, documentation and other reserved addresses (also through auto, or carried inside IPv6) get 400 address_not_public with detail.reason (unspecified, loopback, link_local, multicast, shared_cgnat, unique_local, private or reserved).","properties":{"a":{"oneOf":[{"type":"string","description":"IPv4 or auto"},{"type":"array","items":{"type":"string"}},{"type":"null"}]},"aaaa":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"type":"null"}]},"txt":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"type":"null"}]},"acme_txt":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"type":"null"}]},"https":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}},{"type":"null"}]}}},"Npub":{"type":"string","description":"bech32 npub1... (64-hex also accepted on input)","examples":["npub1g3hqmgcf63p6dphm5grse7d29s8aw3kmr7zpcfvcdffjr6v8um5sumy96u"]},"Session":{"type":"object","properties":{"pubkey":{"type":"string"},"npub":{"$ref":"#/components/schemas/Npub"},"expires_at":{"type":"string","format":"date-time"},"csrf":{"type":"string","description":"Only in the POST answer."},"paid":{"type":"boolean","description":"The account has a paid order; false = \"new unpaid\" limits apply."},"pow_required":{"type":"boolean","description":"The account's gated signed requests need NIP-13 proof of work (see nip98)."},"pow_bits":{"type":"integer"}}},"Account":{"type":"object","properties":{"exists":{"type":"boolean"},"pubkey":{"type":"string"},"npub":{"$ref":"#/components/schemas/Npub"},"created_at":{"type":["string","null"],"format":"date-time"},"state":{"type":"string","enum":["active","frozen","banned","deleted"]},"tier":{"type":"string","enum":["new","established","manual"]},"paid":{"type":"boolean","description":"At least one fulfilled paid order (or set so by us). False = \"new unpaid\" limits."},"pow_required":{"type":"boolean","description":"This account's gated signed requests need NIP-13 proof of work (see nip98)."},"pow_bits":{"type":"integer","description":"Leading zero bits required; 0 = proof of work off."},"npub_limits":{"type":"object","description":"Allowances per tier (new_unpaid, paid) and the windows shared by all new unpaid accounts."},"credit_sat":{"type":"integer","const":0,"description":"Reserved for a later credit model."},"limits":{"type":"object","additionalProperties":{"type":"integer"}},"usage":{"type":"object","properties":{"live_objects":{"type":"integer"},"new_today":{"type":"integer"},"open_invoices":{"type":"integer"},"open_onchain":{"type":"integer"}}},"notify":{"type":"object","properties":{"dm":{"type":"boolean"},"nip04":{"type":"boolean"}}},"payment_model":{"type":"string","const":"pay_as_you_go"},"recovery":{"type":["object","null"],"properties":{"recovery_npub":{"type":"string"},"effective_at":{"type":"string","format":"date-time"}}}}},"AccountPatch":{"type":"object","additionalProperties":false,"properties":{"notify_dm":{"type":"boolean"},"notify_nip04":{"type":"boolean"}}},"OwnedObject":{"type":"object","properties":{"type":{"type":"string","enum":["zone","hostname"]},"name":{"type":"string"},"kind":{"type":"string","enum":["primary","secondary"]},"status":{"type":"string","enum":["active","grace","expired","suspended"]},"expires_at":{"type":"string","format":"date-time"},"days_left":{"type":"integer"},"auto_renew":{"type":"boolean"},"auto_renew_period":{"type":"string","enum":["30d","1y"]},"health":{"type":["string","null"],"description":"Secondary zones only."}}},"Claim":{"type":"object","additionalProperties":false,"properties":{"zone":{"type":"string"},"hostname":{"type":"string"},"token":{"type":"string"}},"required":["token"]},"Recovery":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string","enum":["token","recovery_npub"]},"object_type":{"type":["string","null"],"enum":["zone","hostname",null],"description":"Token recoveries only; null for a whole-account recovery."},"name":{"type":["string","null"],"description":"The zone or hostname (FQDN, trailing dot) of a token recovery."},"old_npub":{"$ref":"#/components/schemas/Npub"},"new_npub":{"$ref":"#/components/schemas/Npub"},"started_at":{"type":"string","format":"date-time"},"effective_at":{"type":"string","format":"date-time"},"state":{"type":"string","enum":["pending","done","cancelled"]}}},"Transfer":{"type":"object","properties":{"id":{"type":"string"},"object_type":{"type":"string","enum":["zone","hostname"]},"object":{"type":"string"},"from_npub":{"$ref":"#/components/schemas/Npub"},"to_npub":{"$ref":"#/components/schemas/Npub"},"expires_at":{"type":"string","format":"date-time"},"state":{"type":"string","enum":["offered","accepted","cancelled","declined","expired"]}}},"ApiKeyCreate":{"type":"object","additionalProperties":false,"required":["scope"],"properties":{"label":{"type":"string","maxLength":64},"scope":{"type":"object","required":["objects","access"],"properties":{"objects":{"type":"array","items":{"type":"string","examples":["*","zone:example.com","host:myhost"]}},"access":{"type":"string","enum":["read","write"]},"spend_credit":{"type":"boolean","const":false,"description":"Reserved for a later credit model; true gives 400 invalid_scope."}}},"expires_at":{"type":"integer","description":"Unix seconds, in the future, at most 2 years ahead. Answers show it as ISO 8601."}}},"ApiKey":{"type":"object","properties":{"id":{"type":"string"},"key":{"type":"string","description":"jdk_..., only in the POST answer"},"label":{"type":"string"},"scope":{"type":"object"},"created_at":{"type":"string","format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"last_used_day":{"type":["string","null"]},"revoked":{"type":"boolean"}}},"Order":{"type":"object","additionalProperties":false,"required":["product"],"properties":{"product":{"type":"string","enum":["zone_create","zone_renew","zone_queries","ddns_create","ddns_renew","secondary_create","domain_register","domain_renew","domain_transfer"]},"period":{"type":"string","enum":["30d","1y","1m","2y","3y","4y","5y","6y","7y","8y","9y","10y"],"description":"1m only for zone_queries (the default there). Domain products take 1y to 10y (default 1y); domain_transfer only 1y."},"domain":{"type":"string","description":"domain_* products. example.com (second level under an offered TLD)."},"registrant":{"$ref":"#/components/schemas/Registrant"},"attestation":{"type":"boolean","const":true,"description":"domain_register and domain_transfer. \"I am authorised by the named registrant to register this domain for them, and the registrant accepts the registration agreement.\" (400 attestation_required carries the text, agreement_url and agreement_version.)"},"nameservers":{"description":"domain_register / domain_transfer. \"ours\" (default for a registration) or 2-13 host names. A new registration always starts on our nameservers; yours are set when the new-name hold ends (about 3 hours, after a phishing-list check). A transfer needs this or host_zone.","oneOf":[{"type":"string","const":"ours"},{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":13}]},"host_zone":{"type":"boolean","description":"Also host the zone here for a year (adds hosting_addon_sat); its DS is pushed to the registry."},"auth_code":{"type":"string","minLength":4,"maxLength":64,"description":"domain_transfer only; never shown back."},"privacy":{"type":"string","enum":["full"]},"zone":{"type":"string"},"hostname":{"type":"string"},"primaries":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":4},"pay":{"type":"string","enum":["lightning","onchain","both","check"],"default":"lightning","description":"onchain and both need an order of at least 5,000 sats (400 onchain_minimum). check = the free checks only (204; for domain products 200 with the quote, from the same 60 s cache and within the same limits as GET /v1/domains/check)."}}},"OrderResult":{"type":"object","required":["invoice"],"properties":{"invoice":{"$ref":"#/components/schemas/Invoice"}}},"Invoice":{"type":"object","properties":{"id":{"type":"string"},"purpose":{"type":"string","enum":["order","lnurl"]},"state":{"type":"string","enum":["created","seen","partially_paid","paid","fulfilling","fulfilled","failed","expired","underpaid","late_paid","unallocated","under_review"],"description":"paid in time -> paid -> fulfilled; refused after payment -> failed (refundable); nothing paid by expiry -> expired; less than the amount -> underpaid (refundable; the order does not run); paid after expiry -> late_paid (refundable; the order does not run); under_review = an address check failed, do not pay."},"amount_sat":{"type":"integer"},"received_sat":{"type":"integer"},"created_at":{"type":"string","format":"date-time"},"paid_at":{"type":["string","null"],"format":"date-time"},"order":{"type":["object","null"]},"lightning":{"type":["object","null"],"properties":{"bolt11":{"type":"string"},"payment_hash":{"type":"string"},"expires_at":{"type":"string","format":"date-time"}}},"onchain":{"type":["object","null"],"properties":{"address":{"type":"string"},"bip21":{"type":"string"},"expires_at":{"type":"string","format":"date-time"},"min_confirmations":{"type":"integer","const":1},"outputs":{"type":"array","items":{"type":"object","properties":{"txid":{"type":"string"},"vout":{"type":"integer"},"value_sat":{"type":"integer"},"confirmations":{"type":"integer"},"state":{"type":"string","enum":["seen","credited","dropped","reorged"]}}}}}},"result":{"type":["object","null"],"description":"Object status; a new token (and a TSIG secret for secondary zones) appears once, on the first GET after fulfilment, within 1 h."},"error":{"type":["object","null"]},"fulfilled_at":{"type":["string","null"],"format":"date-time"},"refundable_sat":{"type":"integer","description":"What a refund request may ask for: money not applied plus a kept overpayment, less open requests."},"note":{"type":"string"}}},"LedgerLine":{"type":"object","properties":{"id":{"type":"integer"},"ts":{"type":"string","format":"date-time"},"amount_sat":{"type":"integer","description":"From the customer's side: + paid in, - applied to the order or refunded."},"kind":{"type":"string","enum":["receipt","spend","tip","reversal","refund","unalloc","adjust","forfeit"]},"ref":{"type":"string"},"object":{"type":["string","null"]},"invoice_id":{"type":["string","null"]}}},"RefundRequest":{"type":"object","additionalProperties":false,"required":["invoice_id","rail","destination"],"properties":{"invoice_id":{"type":"string"},"amount_sat":{"type":"integer","minimum":1000,"description":"Default: the invoice's refundable_sat."},"rail":{"type":"string","enum":["onchain","lightning"]},"destination":{"type":"string","description":"bc1 address, or a Lightning address / LNURL"}}},"Refund":{"type":"object","properties":{"id":{"type":"string"},"amount_sat":{"type":"integer"},"rail":{"type":"string"},"state":{"type":"string","enum":["requested","approved","paid","rejected","cancelled"]},"payout_ref":{"type":["string","null"]},"fee_sat":{"type":["integer","null"]}}},"ObjectSettings":{"type":"object","additionalProperties":false,"properties":{"auto_renew":{"type":"boolean","description":"Not offered at launch (pay-as-you-go): true gives 400 not_offered."},"auto_renew_period":{"type":"string","enum":["30d","1y"]},"auto_buy_queries":{"type":"boolean","description":"Not offered at launch: true gives 400 not_offered."},"token_disabled":{"type":"boolean","description":"Needs a step-up signature. false is refused with 409 token_reissue_required when the object changed owner (transfer or recovery) after its token was issued; that token was retired, so issue a new one with POST .../token (detail.route names it)."}}},"Lnurl":{"type":"object","properties":{"pay_id":{"type":"string"},"lnurl":{"type":"string","description":"bech32 LNURL1..."},"url":{"type":"string","description":"https://pay.<host>/lnurlp/<pay_id> (LUD-06 payRequest)"},"lightning_address":{"type":"string","examples":["abcdefghijkm@pay.satsdns.com"]},"rate":{"type":"object","properties":{"sat_per_30_days":{"type":"integer"},"min_sat":{"type":"integer"},"max_sat":{"type":"integer"}}},"note":{"type":"string"}}},"SecondaryCreate":{"type":"object","additionalProperties":false,"required":["zone","primaries"],"properties":{"zone":{"type":"string"},"ns_ticket":{"type":"string","description":"As for /v1/zones/create (ZoneCreateBody)"},"previous_token":{"type":"string","description":"As for /v1/zones/create (ZoneCreateBody)"},"primaries":{"type":"array","items":{"type":"string","description":"IP literal","global unicast":null},"minItems":1,"maxItems":4}}},"SecondaryStatus":{"type":"object","properties":{"zone":{"type":"string"},"kind":{"type":"string","const":"secondary"},"status":{"type":"string","enum":["creating","active","grace","expired","suspended","removed"]},"primaries":{"type":"array","items":{"type":"string"}},"tsig_name":{"type":"string"},"tsig":{"type":"object","description":"Only in create and rotate answers; shown once, never stored by dns-api.","properties":{"name":{"type":"string"},"algorithm":{"type":"string","const":"hmac-sha256"},"secret":{"type":"string"}}},"tsig_note":{"type":"string","description":"With tsig"},"transfer_source_ips":{"type":"array","items":{"type":"string"}},"notify_to":{"type":"array","items":{"type":"string"}},"dnssec_mode":{"type":"string","enum":["unknown","presigned","unsigned"]},"health":{"type":"string","enum":["pending","ok","failing","stale","too_large","capacity","refused_primary","suspended"],"description":"suspended while the zone is suspended (suspend_reason too_large or capacity when over the limits; last_error says which)"},"serial":{"type":["integer","null"]},"first_transfer_at":{"type":["string","null"],"format":"date-time"},"last_transfer_at":{"type":["string","null"],"format":"date-time"},"last_error":{"type":["string","null"]},"failing_since":{"type":["string","null"],"format":"date-time"},"records":{"type":["integer","null"],"description":"Record count at the last transfer, DNSSEC records included (limit 5,000)"},"config_examples":{"type":"object","description":"Configuration snippets for the customer's primary; GET shows <secret> in place of the secret, create and rotate the real one.","properties":{"bind":{"type":"string"},"knot":{"type":"string"},"nsd":{"type":"string"},"powerdns":{"type":"string"}}},"notes":{"type":"array","items":{"type":"string"}}}},"XfrPeers":{"type":"object","properties":{"zone":{"type":"string"},"peers":{"type":"array","items":{"type":"object","properties":{"address":{"type":"string"},"tsig":{"type":"boolean"},"tsig_name":{"type":["string","null"]},"tsig_secret":{"type":"string","description":"PUT only, for a key made by that PUT; shown once. A kept TSIG peer keeps its key and gets no secret."},"tsig_algorithm":{"type":"string","const":"hmac-sha256","description":"With tsig_secret."}}}},"transfer_from":{"type":"array","items":{"type":"string"},"description":"Our addresses the peers transfer from"},"note":{"type":"string","description":"PUT only"},"tsig_note":{"type":"string","description":"PUT only, when a secret is shown"}}},"LnurlPayRequest":{"type":"object","properties":{"tag":{"type":"string","const":"payRequest"},"callback":{"type":"string"},"minSendable":{"type":"integer"},"maxSendable":{"type":"integer"},"metadata":{"type":"string"},"commentAllowed":{"type":"integer","const":0}}},"LnurlInvoice":{"type":"object","properties":{"pr":{"type":"string"},"routes":{"type":"array","maxItems":0},"verify":{"type":"string"}}},"LnurlError":{"type":"object","properties":{"status":{"type":"string","const":"ERROR"},"reason":{"type":"string"}}},"XfrPeersPut":{"type":"object","additionalProperties":false,"required":["peers"],"properties":{"peers":{"type":"array","maxItems":2,"items":{"type":"object","additionalProperties":false,"required":["address"],"properties":{"address":{"type":"string","description":"IPv4 literal"},"tsig":{"type":"boolean","default":true}}}}}},"SecondaryBlock":{"type":"object","description":"Compact secondary status, also merged into GET /v1/zones/{zone}","properties":{"primaries":{"type":"array","items":{"type":"string"}},"tsig_name":{"type":"string"},"transfer_source_ips":{"type":"array","items":{"type":"string"}},"notify_to":{"type":"array","items":{"type":"string"}},"dnssec_mode":{"type":"string","enum":["unknown","presigned","unsigned"]},"health":{"type":"string","enum":["pending","ok","failing","stale","too_large","capacity","refused_primary","suspended"],"description":"suspended while the zone is suspended (suspend_reason too_large or capacity when over the limits; last_error says which)"},"serial":{"type":["integer","null"]},"first_transfer_at":{"type":["string","null"],"format":"date-time"},"last_transfer_at":{"type":["string","null"],"format":"date-time"},"last_error":{"type":["string","null"]},"failing_since":{"type":["string","null"],"format":"date-time"},"records":{"type":["integer","null"],"description":"Record count at the last transfer, DNSSEC records included (limit 5,000)"}}},"SecondaryCreated":{"allOf":[{"$ref":"#/components/schemas/ZoneStatus"},{"type":"object","properties":{"kind":{"type":"string","const":"secondary"},"token":{"type":"string","description":"jdz_..., shown once"},"token_note":{"type":"string"},"tsig":{"type":"object","description":"Only in create and rotate answers; shown once, never stored by dns-api.","properties":{"name":{"type":"string"},"algorithm":{"type":"string","const":"hmac-sha256"},"secret":{"type":"string"}}},"tsig_note":{"type":"string"},"transfer_source_ips":{"type":"array","items":{"type":"string"}},"notify_to":{"type":"array","items":{"type":"string"}},"config_examples":{"type":"object","description":"Configuration snippets for the customer's primary; GET shows <secret> in place of the secret, create and rotate the real one.","properties":{"bind":{"type":"string"},"knot":{"type":"string"},"nsd":{"type":"string"},"powerdns":{"type":"string"}}},"notes":{"type":"array","items":{"type":"string"}},"secondary":{"$ref":"#/components/schemas/SecondaryBlock"}}}]},"SecondaryDnssec":{"type":"object","description":"GET /v1/zones/{zone}/dnssec for a secondary zone: what the customer's own signer publishes; 404 not_found before the first transfer or while suspended.","properties":{"zone":{"type":"string"},"mode":{"type":"string","enum":["presigned","unsigned"]},"dnskey":{"type":"array","items":{"type":"string"}},"cds":{"type":"array","items":{"type":"string"}},"cdnskey":{"type":"array","items":{"type":"string"}},"ds_from_cds":{"type":"array","items":{"type":"string"}},"ds_from_dnskey":{"type":"array","items":{"type":"string"}},"rrsig_min_expiry":{"type":["string","null"],"format":"date-time","description":"The earliest RRSIG expiry in the zone at the last check (dns-infra's health file); null when unsigned or unknown"},"note":{"type":"string"}}},"Registrant":{"type":"object","additionalProperties":false,"description":"The registrant of record (the buyer names them; SatsDNS is a reseller only). Plain Latin letters, digits and the characters . , ' & / # ( ) + - only (transliterate other scripts). A real full name (first and last) or an organization; the email must accept mail (MX record) and is where the registrar sends the ICANN verification link. Registrants in a few sanctioned countries are refused (403 registrant_refused). Phone and postal address are mandatory: the registrar's terms and ICANN's accuracy rules require accurate registrant contact data, and wrong or missing data can get the domain suspended or cancelled (400 invalid_registrant, detail.field). WHOIS privacy (always full) keeps them out of public view.","required":["name","email","phone","address1","city","postal_code","country"],"properties":{"name":{"type":"string","minLength":3,"maxLength":100},"organization":{"type":"string","maxLength":100},"email":{"type":"string","maxLength":254},"phone":{"type":"string","pattern":"^\\+[0-9]{1,3}\\.[0-9]{4,14}$","description":"+CC.NUMBER, e.g. +1.6045551234"},"address1":{"type":"string","maxLength":100},"address2":{"type":"string","maxLength":100},"city":{"type":"string","maxLength":60},"state":{"type":"string","maxLength":60},"postal_code":{"type":"string","maxLength":16},"country":{"type":"string","pattern":"^[A-Z]{2}$","description":"ISO 3166 alpha-2"}}},"DomainCheck":{"type":"object","properties":{"domain":{"type":"string"},"tld":{"type":"string"},"years":{"type":"integer"},"available":{"type":["boolean","null"]},"premium":{"type":"boolean"},"offered":{"type":"boolean"},"reason":{"type":"string","description":"premium or name_blocked (our own or protected names, or blocked by us)"},"managed_here":{"type":"boolean"},"prices_sat":{"type":"object","description":"register (or transfer when taken) and renew, each {price_sat, years} or {error}","additionalProperties":true},"hosting_addon_sat":{"type":"integer","description":"added when host_zone is true"},"order":{"type":"object","properties":{"route":{"type":"string"},"product":{"type":"string"},"period":{"type":"string"}}}}},"DomainStatus":{"type":"object","properties":{"domain":{"type":"string"},"status":{"type":"string","enum":["registering","transfer_pending","active","expired","redemption","suspended","failed","transferred_out","deleted"],"description":"expired = past expires_at, renewable until renew_until; redemption = after that (restore by hand: ask us)."},"registered_at":{"type":["string","null"],"format":"date-time"},"expires_at":{"type":["string","null"],"format":"date-time"},"days_left":{"type":["integer","null"]},"nameservers":{"type":"array","items":{"type":"string"}},"uses_our_nameservers":{"type":"boolean"},"nameservers_pending":{"type":["array","null"],"items":{"type":"string"},"description":"The buyer's nameservers, applied when the new-name hold ends (hold_until)."},"hold_until":{"type":["string","null"],"format":"date-time"},"hold_ends_at":{"type":["string","null"],"format":"date-time","description":"End of the new-name hold (3 h after a registration; our nameservers until then), null once over."},"hosted_zone":{"type":"object","properties":{"requested":{"type":"boolean"},"state":{"type":["string","null"],"enum":["pending","active","failed",null]}}},"dnssec":{"type":"object","properties":{"state":{"type":["string","null"],"enum":["pending","pushed","failed",null]},"ds":{"type":"array","items":{"type":"object"}}}},"locked":{"type":["boolean","null"]},"privacy":{"type":"string","enum":["full"]},"registrant":{"type":["object","null"],"description":"Only on GET /v1/domains/{domain}, read from the registrar on demand (nothing of the registrant is stored here); null in lists, in order results and when it cannot be read now.","properties":{"name":{"type":"string"},"email":{"type":"string"},"organization":{"type":["string","null"]},"country":{"type":"string"}}},"registrant_verification":{"type":"object","properties":{"state":{"type":"string","enum":["pending","verified","unknown"]},"deadline":{"type":"string","format":"date-time"},"note":{"type":"string","description":"The 15-day rule: unverified -> the registrar suspends; not refunded."}}},"transfer_lock_until":{"type":["string","null"],"format":"date-time"},"auto_renew":{"type":"boolean","const":false},"renew_until":{"type":["string","null"],"format":"date-time"},"sponsoring_registrar":{"type":"string"},"warning":{"type":"string"},"abuse":{"type":"object"},"order_pending":{"type":"object","properties":{"order_id":{"type":"string"},"action":{"type":"string"},"state":{"type":"string","enum":["pending","needs_review","waiting_for_funding"],"description":"waiting_for_funding = paid, the registrar account is being topped up (up to 24 h, then refundable); needs_review = the registrar reported a problem (refundable by itself after 3 days once the registrar shows the money returned)"},"since":{"type":"string","format":"date-time"},"note":{"type":"string"}}}}},"DomainOrderResult":{"type":"object","description":"Invoice.result of a domain order. token (jdd_...) appears once, on the first GET after fulfilment.","properties":{"domain":{"type":"string"},"order_id":{"type":"string"},"action":{"type":"string","enum":["register","renew","transfer"]},"years":{"type":"integer"},"order_state":{"type":"string","enum":["completed","pending","needs_review"]},"note":{"type":"string"},"status":{"$ref":"#/components/schemas/DomainStatus"},"token":{"type":"string"}}},"DsRecord":{"oneOf":[{"type":"string","description":"\"key_tag algorithm digest_type digest\""},{"type":"object","additionalProperties":false,"required":["key_tag","algorithm","digest_type","digest"],"properties":{"key_tag":{"type":"integer","minimum":0,"maximum":65535},"algorithm":{"type":"integer","enum":[8,10,13,14,15,16]},"digest_type":{"type":"integer","enum":[2,4]},"digest":{"type":"string","description":"hex","64 (SHA-256) or 96 (SHA-384) characters":null}}}]},"AbuseReport":{"type":"object","additionalProperties":false,"required":["domain","category","details"],"properties":{"domain":{"type":"string","description":"a name served or sold here now"},"category":{"type":"string","enum":["phishing","malware","spam","botnet","fraud","csam","trademark","other"]},"details":{"type":"string","minLength":10,"maxLength":5000},"contact":{"type":"string","maxLength":300,"description":"optional","how to reach the reporter":null}}},"AbuseAck":{"type":"object","properties":{"id":{"type":"string"},"domain":{"type":"string"},"received_at":{"type":"string","format":"date-time"},"respond_by":{"type":"string","format":"date-time","description":"5 business days after receipt"},"note":{"type":"string"}}}}},"paths":{"/v1/zones/create/{period}":{"post":{"tags":["paid"],"summary":"Host a zone (500 sats for 30 days, 5,000 for a year)","description":"The zone gets its own nameserver pair (ZoneCreateBody): ask without ns_ticket, set detail.expected_ns at your registrar, then send the request with ns_ticket. If the answer to a paid request is lost (timeout), the L402 retry of that payment returns the zone with a new token. Errors: 409 delegation_missing / delegation_mismatch (detail.expected_ns, found_ns; without expected_ns and with detail.registered false: the domain is not registered yet), ns_ticket_invalid, ns_offers_exhausted, zone_reserved, domain_owner_only, zone_exists, zone_clash; 429 ns_offer_limit; 503 delegation_check_unavailable / delegation_check_busy / ns_offers_full.","parameters":[{"$ref":"#/components/parameters/period"}],"security":[{"l402":[]},{"cashu":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneCreateBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneStatus"}}}},"402":{"$ref":"#/components/responses/PaymentRequired"},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/renew/{period}":{"post":{"tags":["paid"],"summary":"Extend a zone (500 / 5,000 sats); counts from the current expiry","parameters":[{"$ref":"#/components/parameters/period"}],"security":[{"l402":[]},{"cashu":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneBody"}}}},"responses":{"200":{"description":"Renewed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneStatus"}}}},"402":{"$ref":"#/components/responses/PaymentRequired"},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/queries/1m":{"post":{"tags":["paid"],"summary":"One million more queries this UTC month (200 sats)","security":[{"l402":[]},{"cashu":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneBody"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneStatus"}}}},"402":{"$ref":"#/components/responses/PaymentRequired"}}}},"/v1/ddns/create/{period}":{"post":{"tags":["paid"],"summary":"Buy a dynamic-DNS hostname under dynkite.com (200 / 2,000 sats)","parameters":[{"$ref":"#/components/parameters/period"}],"security":[{"l402":[]},{"cashu":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnameBody"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostStatus"}}}},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/ddns/renew/{period}":{"post":{"tags":["paid"],"summary":"Extend a hostname (200 / 2,000 sats)","parameters":[{"$ref":"#/components/parameters/period"}],"security":[{"l402":[]},{"cashu":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostnameBody"}}}},"responses":{"200":{"description":"Renewed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostStatus"}}}},"402":{"$ref":"#/components/responses/PaymentRequired"}}}},"/v1/zones/{zone}":{"parameters":[{"$ref":"#/components/parameters/zone"}],"get":{"tags":["zones"],"summary":"Zone status, expiry, limits and query use","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ZoneStatus"}}}},"401":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["zones"],"summary":"Remove the zone now (no refund)","description":"Remove the zone's NS records at your registrar first (or right after): until the registry stops listing them, and for 90 days, the name stays reserved for you (this account, or this token sent as previous_token to /v1/zones/create).","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"Removed","content":{"application/json":{"schema":{"type":"object","properties":{"zone":{"type":"string"},"status":{"type":"string"},"reserved_until":{"type":"string","format":"date-time"},"note":{"type":"string"}}}}}},"401":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/{zone}/token":{"parameters":[{"$ref":"#/components/parameters/zone"}],"post":{"tags":["zones"],"summary":"Replace the management token","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"New token (the old one stops working)"}}}},"/v1/zones/{zone}/dnssec":{"parameters":[{"$ref":"#/components/parameters/zone"}],"get":{"tags":["zones"],"summary":"DS, CDS and CDNSKEY data for the registrar","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/Dnssec"},{"$ref":"#/components/schemas/SecondaryDnssec"}]}}}},"404":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/{zone}/records":{"parameters":[{"$ref":"#/components/parameters/zone"}],"get":{"tags":["records"],"summary":"List rrsets (SOA and apex NS marked managed)","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"parameters":[{"name":"name","in":"query","schema":{"type":"string"}},{"name":"type","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"OK"}}},"post":{"tags":["records"],"summary":"Create or replace one rrset","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RRset"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeResult"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/RateLimited"}}},"patch":{"tags":["records"],"summary":"Up to 100 rrset changes, applied atomically","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["rrsets"],"properties":{"rrsets":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/RRset"}}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeResult"}}}}}}},"/v1/zones/{zone}/records/{name}/{type}":{"parameters":[{"$ref":"#/components/parameters/zone"},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"type","in":"path","required":true,"schema":{"type":"string"}}],"put":{"tags":["records"],"summary":"Replace one rrset","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ttl":{"type":"integer"},"records":{"type":"array","items":{"type":"string"}}}}}}},"responses":{"200":{"description":"OK"}}},"delete":{"tags":["records"],"summary":"Delete one rrset","security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK"},"404":{"$ref":"#/components/responses/Error"}}}},"/v1/ddns/{hostname}":{"parameters":[{"$ref":"#/components/parameters/hostname"}],"get":{"tags":["ddns"],"summary":"Hostname status and records","security":[{"hostToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostStatus"}}}}}},"delete":{"tags":["ddns"],"summary":"Release the hostname now","security":[{"hostToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"Removed"}}}},"/v1/ddns/{hostname}/update":{"parameters":[{"$ref":"#/components/parameters/hostname"}],"post":{"tags":["ddns"],"summary":"Set A, AAAA, TXT, ACME TXT, HTTPS (TTL 60)","security":[{"hostToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HostUpdate"}}}},"responses":{"200":{"description":"OK"},"400":{"description":"invalid_body, invalid_record, invalid_address or address_not_public (a or aaaa is not a public address); nothing is changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/ddns/{hostname}/token":{"parameters":[{"$ref":"#/components/parameters/hostname"}],"post":{"tags":["ddns"],"summary":"Replace the hostname token","security":[{"hostToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"New token"}}}},"/nic/update":{"get":{"tags":["ddns"],"summary":"dyndns2 protocol (routers, ddclient, inadyn)","security":[{"dyndnsBasic":[]},{"hostToken":[]}],"parameters":[{"name":"hostname","in":"query","required":true,"schema":{"type":"string"}},{"name":"myip","in":"query","schema":{"type":"string","description":"IPv4 and/or IPv6, comma-separated; default the caller's address"}}],"responses":{"200":{"description":"good <ip> or nochg <ip>","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"description":"dnserr (myip is not an IP address or not a public one) or 911","content":{"text/plain":{"schema":{"type":"string"}}}},"401":{"description":"badauth (missing, wrong or disabled token, or the owning account was deleted), with WWW-Authenticate Basic and a Link header to the dynamic-DNS docs"},"403":{"description":"abuse (hostname suspended or the owning account banned)","content":{"text/plain":{"schema":{"type":"string"}}}}}}},"/v1/info":{"get":{"tags":["free"],"summary":"Nameservers, prices, periods, limits, record types","responses":{"200":{"description":"OK"}}},"head":{"tags":["free"],"summary":"Same as GET, without the body","responses":{"200":{"description":"OK"}}}},"/healthz":{"get":{"tags":["free"],"summary":"Health (dns-api, PowerDNS, database)","responses":{"200":{"description":"OK"},"503":{"description":"Not ready"}}},"head":{"tags":["free"],"summary":"Same as GET, without the body","responses":{"200":{"description":"OK"},"503":{"description":"Not ready"}}}},"/v1/secondary/create/{period}":{"post":{"tags":["paid","secondary"],"summary":"Secondary zone (500 sats for 30 days, 5,000 for a year); returns token and TSIG once","parameters":[{"$ref":"#/components/parameters/period"}],"security":[{"l402":[]},{"cashu":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecondaryCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecondaryCreated"}}}},"400":{"$ref":"#/components/responses/Error"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"503":{"$ref":"#/components/responses/Error"}},"description":"Errors: 400 bad_primary (detail.reason not_ip | port | private | reserved | own | too_many; detail.address), 400 ipv6_primary_unsupported, 409 limit_reached (detail {limit: zones_per_primary, address, max}), 409 secondary_full (detail {limit: secondary_capacity}: secondary DNS is at its total capacity; checked before the 402, so no invoice is made; existing zones are not affected), 409 zone_is_primary (secondary routes on a hosted zone). Limits per secondary zone: 5,000 records (DNSSEC records included) and 4 MiB per transfer; a zone over either is suspended (suspend_reason too_large), a zone that grows past the total capacity is suspended with suspend_reason capacity; the reason is in last_error."}},"/v1/auth/session":{"post":{"tags":["auth"],"summary":"Start a dashboard session (app host only); body {}","description":"An account without a paid order signs in with NIP-13 proof of work on the event (401 pow_required otherwise); the session then needs none.","security":[{"nip98":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","maxProperties":0}}}},"responses":{"201":{"description":"Session started; sets __Host-jdsess","headers":{"Set-Cookie":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Error"}}},"get":{"tags":["auth"],"summary":"Current session","security":[{"session":[]},{"nip98":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Session"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["auth"],"summary":"Log out","parameters":[{"$ref":"#/components/parameters/csrf"}],"security":[{"session":[]},{"nip98":[]}],"responses":{"204":{"$ref":"#/components/responses/NoContent"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/auth/sessions":{"delete":{"tags":["auth"],"summary":"Revoke every session of this account","security":[{"nip98StepUp":[]}],"responses":{"204":{"$ref":"#/components/responses/NoContent"},"401":{"$ref":"#/components/responses/Unauthorized"}}}},"/v1/account":{"get":{"tags":["account"],"summary":"Account (exists=false for an unknown pubkey; nothing is written)","security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"patch":{"tags":["account"],"summary":"Notification settings","parameters":[{"$ref":"#/components/parameters/csrf"}],"security":[{"nip98":[]},{"session":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountPatch"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["account"],"summary":"Delete the account (no live objects; forfeit_credit true if credit is left)","description":"Refused with 409 account_has_domains while the account owns a registered domain (not failed, transferred out or deleted) or has a domain order in progress, and with 409 account_has_objects while it has live zones or hostnames.","security":[{"nip98StepUp":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"forfeit_credit":{"type":"boolean"}}}}}},"responses":{"204":{"$ref":"#/components/responses/NoContent"},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/account/zones":{"get":{"tags":["account"],"summary":"Zones this account owns (both kinds)","security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"zones":{"type":"array","items":{"$ref":"#/components/schemas/OwnedObject"}}}}}}}}}},"/v1/account/hostnames":{"get":{"tags":["account"],"summary":"Dynamic-DNS hostnames this account owns","security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"hostnames":{"type":"array","items":{"$ref":"#/components/schemas/OwnedObject"}}}}}}}}}},"/v1/account/claim":{"post":{"tags":["account"],"summary":"Claim a token-bought zone or hostname; 202 starts a 72 h recovery if another npub owns it","security":[{"nip98":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Claim"}}}},"responses":{"200":{"description":"Claimed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnedObject"}}}},"202":{"description":"Recovery started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recovery"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/account/recovery":{"put":{"tags":["account"],"summary":"Set the recovery npub (effective 72 h later)","security":[{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["recovery_npub"],"properties":{"recovery_npub":{"$ref":"#/components/schemas/Npub"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"$ref":"#/components/responses/Unauthorized"}}},"delete":{"tags":["account"],"summary":"Clear the recovery npub","security":[{"nip98StepUp":[]}],"responses":{"204":{"$ref":"#/components/responses/NoContent"}}}},"/v1/account/recover":{"post":{"tags":["account"],"summary":"Signed by a recovery npub; moves a lost account's objects and credit after 72 h","security":[{"nip98":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["lost_npub","new_npub"],"properties":{"lost_npub":{"$ref":"#/components/schemas/Npub"},"new_npub":{"$ref":"#/components/schemas/Npub"}}}}}},"responses":{"202":{"description":"Recovery started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Recovery"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/account/recoveries":{"get":{"tags":["account"],"summary":"Recoveries for or against this account","security":[{"nip98":[]},{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"recoveries":{"type":"array","items":{"$ref":"#/components/schemas/Recovery"}}}}}}}}}},"/v1/account/recoveries/{id}":{"delete":{"tags":["account"],"summary":"Cancel a pending recovery (current owner or lost account)","parameters":[{"$ref":"#/components/parameters/id"}],"security":[{"nip98StepUp":[]}],"responses":{"204":{"$ref":"#/components/responses/NoContent"},"404":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/{zone}/transfer":{"post":{"tags":["account"],"summary":"Offer the zone to another npub (expires after 72 h)","description":"The answer is {\"transfer\", \"recipient_notified\"}. The recipient gets one DM per object per offer lifetime and at most 5 offer DMs a day (recipient_notified false otherwise; the offer still shows in their GET /v1/account/transfers). At most 3 open offers and 10 new offers per 24 h per account (409 limit_reached, detail.limit offers or offers_per_day). Accepting retires the object's token.","parameters":[{"$ref":"#/components/parameters/zone"},{"$ref":"#/components/parameters/idempotencyKey"}],"security":[{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["to_npub"],"properties":{"to_npub":{"$ref":"#/components/schemas/Npub"}}}}}},"responses":{"201":{"description":"Offered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transfer"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/ddns/{hostname}/transfer":{"post":{"tags":["account"],"summary":"Offer the hostname to another npub","description":"The answer is {\"transfer\", \"recipient_notified\"}. The recipient gets one DM per object per offer lifetime and at most 5 offer DMs a day (recipient_notified false otherwise; the offer still shows in their GET /v1/account/transfers). At most 3 open offers and 10 new offers per 24 h per account (409 limit_reached, detail.limit offers or offers_per_day). Accepting retires the object's token.","parameters":[{"$ref":"#/components/parameters/hostname"},{"$ref":"#/components/parameters/idempotencyKey"}],"security":[{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["to_npub"],"properties":{"to_npub":{"$ref":"#/components/schemas/Npub"}}}}}},"responses":{"201":{"description":"Offered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transfer"}}}}}}},"/v1/account/transfers":{"get":{"tags":["account"],"summary":"Offers made and received","security":[{"nip98":[]},{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"transfers":{"type":"array","items":{"$ref":"#/components/schemas/Transfer"}}}}}}}}}},"/v1/account/transfers/{id}/accept":{"post":{"tags":["account"],"summary":"Accept an offer (the target signs)","parameters":[{"$ref":"#/components/parameters/id"}],"security":[{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","maxProperties":0}}}},"responses":{"200":{"description":"Accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transfer"}}}},"404":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/account/transfers/{id}/decline":{"post":{"tags":["account"],"summary":"Decline an offer","parameters":[{"$ref":"#/components/parameters/id"}],"security":[{"nip98StepUp":[]}],"responses":{"200":{"description":"Declined","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transfer"}}}}}}},"/v1/account/transfers/{id}":{"delete":{"tags":["account"],"summary":"Cancel an offer you made","parameters":[{"$ref":"#/components/parameters/id"}],"security":[{"nip98StepUp":[]}],"responses":{"204":{"$ref":"#/components/responses/NoContent"}}}},"/v1/account/keys":{"get":{"tags":["account"],"summary":"API keys","security":[{"nip98":[]},{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}}}}}}}}},"post":{"tags":["account"],"summary":"Create an API key (shown once)","security":[{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreate"}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKey"}}}},"400":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/account/keys/{id}":{"delete":{"tags":["account"],"summary":"Revoke an API key","parameters":[{"$ref":"#/components/parameters/id"}],"security":[{"nip98StepUp":[]}],"responses":{"204":{"$ref":"#/components/responses/NoContent"}}}},"/v1/account/orders":{"post":{"tags":["billing"],"summary":"Order with its own invoice (Lightning, on-chain or both); pay=check is a free dry run","description":"Counted per npub, not per client address. Every order and pay \"check\" counts against 30 an hour for an account without a paid order (\"new unpaid\"; 300 with a paid order), 200 an hour for the new unpaid accounts of one network (IPv4 /24, IPv6 /48) together and 600 an hour shared by all new unpaid accounts. Invoices: 10 a minute per account; 6 an hour for a new unpaid account (60 with a paid order), 40 an hour per network and 120 an hour shared by all new unpaid accounts, 600 an hour in total. A new unpaid account holds at most 2 open Lightning invoices and 1 open on-chain invoice (429 npub_limit, Retry-After until the oldest expires), and gets at most 5 open nameserver offers and 10 new ones a day (100 a day per network, 300 a day shared). Refusals: 429 npub_limit (this account), network_limit (new unpaid accounts of this network) or global_limit (all new unpaid accounts) with detail.rule; 401 pow_required when the NIP-98 event of a new unpaid account lacks NIP-13 proof of work (see nip98). The first order of a new npub opens its account (100 new accounts a day per IPv4 /24 or IPv6 /48 for signed requests with proof of work, 30 without, 429 rate_limited; 500 a day in total, 503 busy_try_later). Refused orders create no invoice. The numbers are the current defaults; GET /v1/info accounts.npub_limits has the live ones.","parameters":[{"$ref":"#/components/parameters/idempotencyKey"},{"$ref":"#/components/parameters/csrf"}],"security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"responses":{"201":{"description":"Invoice created; the order runs when it is paid in time","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrderResult"}}}},"204":{"$ref":"#/components/responses/NoContent"},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Error"}}}},"/v1/account/invoices":{"get":{"tags":["billing"],"summary":"This account's invoices, newest first (an API key sees only those of objects in its scope)","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size; values outside 1 to 200 are clamped.","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"before","in":"query","required":false,"description":"The `next` value from the previous page (an invoice id); omit for the first page.","schema":{"type":"string"}}],"security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"invoices":{"type":"array","items":{"$ref":"#/components/schemas/Invoice"}},"next":{"type":["string","null"],"description":"Send as `before` to get the next page; null when this page has fewer than limit items (a full last page is followed by an empty one)."}}}}}}}}},"/v1/invoices/{id}":{"get":{"tags":["billing"],"summary":"One invoice; also checks Lightning settlement (at most every 3 s). An API key gets 404 for an invoice of an object outside its scope","parameters":[{"$ref":"#/components/parameters/id"}],"security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Invoice"}}}},"404":{"$ref":"#/components/responses/Error"}}}},"/v1/account/ledger":{"get":{"tags":["billing"],"summary":"Credit movements, newest first (an API key sees only those of objects in its scope)","parameters":[{"name":"limit","in":"query","required":false,"description":"Page size; values outside 1 to 500 are clamped.","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}},{"name":"before","in":"query","required":false,"description":"The `next` value from the previous page (a ledger line id); omit for the first page.","schema":{"type":"integer"}}],"security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"lines":{"type":"array","items":{"$ref":"#/components/schemas/LedgerLine"}},"next":{"type":["integer","null"],"description":"Send as `before` to get the next page; null when this page has fewer than limit items (a full last page is followed by an empty one)."}}}}}}}}},"/v1/account/refunds":{"get":{"tags":["billing"],"summary":"Refund requests","security":[{"nip98":[]},{"session":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"refunds":{"type":"array","items":{"$ref":"#/components/schemas/Refund"}}}}}}}}},"post":{"tags":["billing"],"summary":"Ask for a refund of an invoice's refundable amount (step-up; each is approved by hand)","parameters":[{"$ref":"#/components/parameters/idempotencyKey"}],"security":[{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RefundRequest"}}}},"responses":{"201":{"description":"Requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Refund"}}}},"400":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/{zone}/settings":{"patch":{"tags":["account"],"summary":"Auto-renew, auto-buy queries, token on/off","parameters":[{"$ref":"#/components/parameters/zone"},{"$ref":"#/components/parameters/csrf"}],"security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectSettings"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnedObject"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/ddns/{hostname}/settings":{"patch":{"tags":["account"],"summary":"Auto-renew, token on/off","parameters":[{"$ref":"#/components/parameters/hostname"},{"$ref":"#/components/parameters/csrf"}],"security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectSettings"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnedObject"}}}},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/{zone}/lnurl":{"get":{"tags":["lnurl"],"summary":"The zone's LNURL-pay and Lightning address (404 until created)","parameters":[{"$ref":"#/components/parameters/zone"}],"security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lnurl"}}}},"404":{"$ref":"#/components/responses/Error"}}},"post":{"tags":["lnurl"],"summary":"Create or rotate the zone's pay id","parameters":[{"$ref":"#/components/parameters/zone"}],"security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lnurl"}}}}}}},"/v1/ddns/{hostname}/lnurl":{"get":{"tags":["lnurl"],"summary":"The hostname's LNURL-pay","parameters":[{"$ref":"#/components/parameters/hostname"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lnurl"}}}}}},"post":{"tags":["lnurl"],"summary":"Create or rotate the hostname's pay id","parameters":[{"$ref":"#/components/parameters/hostname"}],"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Lnurl"}}}}}}},"/lnurlp/{pay_id}":{"get":{"tags":["lnurl"],"summary":"LUD-06 payRequest (pro-rata extension, min 100 sats)","parameters":[{"$ref":"#/components/parameters/payId"}],"security":[],"responses":{"200":{"description":"payRequest or LUD error","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/LnurlPayRequest"},{"$ref":"#/components/schemas/LnurlError"}]}}}}}}},"/.well-known/lnurlp/{pay_id}":{"get":{"tags":["lnurl"],"summary":"LUD-16 Lightning address (pay.satsdns.com only)","parameters":[{"$ref":"#/components/parameters/payId"}],"security":[],"responses":{"200":{"description":"payRequest or LUD error","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/LnurlPayRequest"},{"$ref":"#/components/schemas/LnurlError"}]}}}}}}},"/lnurlp/{pay_id}/callback":{"get":{"tags":["lnurl"],"summary":"Invoice for amount msat (whole sats); description_hash = sha256(metadata)","description":"For pay_id \"zaps\" (the Lightning address zaps@satsdns.com, whose LUD-16 answer the site serves at /.well-known/lnurlp/zaps): 1 to 100,000 sats, an optional comment (LUD-12, up to 280 characters) and an optional NIP-57 zap request in nostr; with a zap request the description_hash is sha256 of that JSON, and a kind 9735 receipt goes to its relays once paid.","parameters":[{"$ref":"#/components/parameters/payId"},{"name":"amount","in":"query","required":true,"schema":{"type":"integer"}},{"name":"nostr","in":"query","required":false,"description":"NIP-57 zap request (kind 9734 event, JSON), pay_id \"zaps\" only","schema":{"type":"string"}},{"name":"comment","in":"query","required":false,"description":"LUD-12 comment, pay_id \"zaps\" only (commentAllowed 280)","schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"Invoice or LUD error","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/LnurlInvoice"},{"$ref":"#/components/schemas/LnurlError"}]}}}},"429":{"$ref":"#/components/responses/Error"}}}},"/lnurlp/verify/{payment_hash}":{"get":{"tags":["lnurl"],"summary":"LUD-21 verify","parameters":[{"name":"payment_hash","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{64}$"}}],"security":[],"responses":{"200":{"description":"Status","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","const":"OK"},"settled":{"type":"boolean"},"preimage":{"type":["string","null"]},"pr":{"type":"string"}}}}}}}}},"/v1/zones/{zone}/secondary":{"get":{"tags":["secondary"],"summary":"Secondary zone status (409 zone_is_primary for hosted zones)","parameters":[{"$ref":"#/components/parameters/zone"}],"security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecondaryStatus"}}}},"409":{"$ref":"#/components/responses/Error"}}},"put":{"tags":["secondary"],"summary":"Replace the primaries (owners need a step-up signature)","parameters":[{"$ref":"#/components/parameters/zone"}],"security":[{"zoneToken":[]},{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["primaries"],"properties":{"primaries":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":4}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecondaryStatus"}}}},"400":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}},"description":"On a zone suspended as stale this brings it back (the customer fixed the primary); other suspensions are lifted only by us. Errors: 400 bad_primary (detail.reason not_ip | port | private | reserved | own | too_many; detail.address), 400 ipv6_primary_unsupported, 409 limit_reached (detail {limit: zones_per_primary, address, max}), 409 zone_is_primary (secondary routes on a hosted zone)."}},"/v1/zones/{zone}/secondary/tsig":{"post":{"tags":["secondary"],"summary":"Rotate the TSIG key; the new secret is shown once; transfers fail until the primary is updated","parameters":[{"$ref":"#/components/parameters/zone"}],"security":[{"zoneToken":[]},{"nip98StepUp":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecondaryStatus"}}}},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/zones/{zone}/xfr-peers":{"get":{"tags":["secondary"],"summary":"Outside secondaries allowed to AXFR this hosted zone","parameters":[{"$ref":"#/components/parameters/zone"}],"security":[{"zoneToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XfrPeers"}}}},"409":{"$ref":"#/components/responses/Error"}}},"put":{"tags":["secondary"],"summary":"Replace the peers (at most 2); TSIG secrets for new peers shown once","parameters":[{"$ref":"#/components/parameters/zone"}],"security":[{"zoneToken":[]},{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/XfrPeersPut"}}}},"responses":{"200":{"description":"OK; new TSIG peers carry tsig_secret once","content":{"application/json":{"schema":{"$ref":"#/components/schemas/XfrPeers"}}}},"400":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}},"description":"Errors: 400 bad_primary (detail.reason as for primaries), 400 too_many_peers (detail.max), 409 zone_is_secondary (xfr-peers on a secondary zone)."}},"/v1/domains/check":{"get":{"tags":["domains","free"],"summary":"Availability and prices in sats (free, rate-limited; asks the registrar)","description":"Answers 404 not_offered while registration is closed. Prices are quotes from the registrar's current USD price and the bitcoin price; the order re-quotes, and the paid order checks availability and the price once more before buying (a rise above 2% fails the order, refundable). Answers are cached for 60 s; a name not in the cache counts against 6 checks a minute per client address, 10 per client network (IPv4 /24, IPv6 /48) and 20 in total (429). A signed check (NIP-98, session or API key) counts per account instead - 3 a minute without a paid order (6 with one), 5 a minute per network and 10 a minute shared by all accounts without a paid order (429 npub_limit / network_limit / global_limit), and needs NIP-13 proof of work while the account has no paid order (401 pow_required). While the registrar asks us to slow down, 503 registration_unavailable with Retry-After.","security":[{},{"nip98":[]},{"session":[]},{"apiKey":[]}],"parameters":[{"name":"domain","in":"query","required":true,"schema":{"type":"string"}},{"name":"years","in":"query","schema":{"type":"integer","minimum":1,"maximum":10,"default":1}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainCheck"}}}},"400":{"$ref":"#/components/responses/Error"},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/Error"}}}},"/v1/account/domains":{"get":{"tags":["domains","account"],"summary":"The account's registered domains","security":[{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"domains":{"type":"array","items":{"$ref":"#/components/schemas/DomainStatus"}}}}}}}}}},"/v1/domains/{domain}":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["domains"],"summary":"Domain status (expiry, nameservers, DNSSEC, lock, verification, pending orders)","security":[{"domainToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/Error"}}}},"/v1/domains/{domain}/nameservers":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"put":{"tags":["domains"],"summary":"Set nameservers (\"ours\" or 2-13 hosts); queued while a new name is in its hold","security":[{"domainToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["nameservers"],"properties":{"nameservers":{"oneOf":[{"type":"string","const":"ours"},{"type":"array","items":{"type":"string"},"minItems":2,"maxItems":13}]}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}},"400":{"$ref":"#/components/responses/Error"},"403":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"},"503":{"$ref":"#/components/responses/Error"}}}},"/v1/domains/{domain}/dnssec":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"put":{"tags":["domains"],"summary":"Set the DS at the registry (custom nameservers only; a zone hosted here is pushed for you)","security":[{"domainToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["ds"],"properties":{"ds":{"type":"array","minItems":1,"maxItems":1,"items":{"$ref":"#/components/schemas/DsRecord"},"description":"one DS: the registrar keeps one per domain (a key roll is one swap)"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}},"400":{"$ref":"#/components/responses/Error"},"409":{"$ref":"#/components/responses/Error"}}},"delete":{"tags":["domains"],"summary":"Remove every DS (sensitive)","security":[{"domainToken":[]},{"nip98StepUp":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}}}}},"/v1/domains/{domain}/dnssec/sync":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["domains"],"summary":"Push the DS of the zone hosted here to the registry again","security":[{"domainToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}},"409":{"$ref":"#/components/responses/Error"},"503":{"$ref":"#/components/responses/Error"}}}},"/v1/domains/{domain}/lock":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"put":{"tags":["domains"],"summary":"Registrar lock on or off (off is sensitive)","security":[{"domainToken":[]},{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["locked"],"properties":{"locked":{"type":"boolean"}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}}}}},"/v1/domains/{domain}/auth-code":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["domains"],"summary":"Transfer out - the auth code, at once (sensitive; unlocks the domain)","description":"Given also during a payment dispute or an abuse case of another kind. Refused (409 abuse_hold) only while a phishing, malware or CSAM report on the name is being acted on (evidence confirmed by us). Refused for 60 days after a registration or transfer in (registry rule, 409 transfer_locked_60d with detail.until). At most 5 a day. The code is not stored here; the owner gets a DM. When an account owns the domain, only the owner's NIP-98 signature gets the code (the domain token gets 401 step_up_required); a domain without an owner account gets it with its token.","security":[{"domainToken":[]},{"nip98StepUp":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"domain":{"type":"string"},"auth_code":{"type":"string"},"locked":{"type":"boolean"},"note":{"type":"string"}}}}}},"409":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/v1/domains/{domain}/registrant":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"put":{"tags":["domains"],"summary":"Change the registrant (passed to the registrar; free; may need email confirmation)","security":[{"domainToken":[]},{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["registrant","attestation"],"properties":{"registrant":{"$ref":"#/components/schemas/Registrant"},"attestation":{"type":"boolean","const":true}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/domains/{domain}/transfer":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"put":{"tags":["domains"],"summary":"Correct the auth code of a transfer in progress (sensitive)","security":[{"domainToken":[]},{"nip98StepUp":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["auth_code"],"properties":{"auth_code":{"type":"string","minLength":4,"maxLength":64}}}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainStatus"}}}},"409":{"$ref":"#/components/responses/Error"}}}},"/v1/domains/{domain}/token":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["domains"],"summary":"Replace the domain token (sensitive)","security":[{"domainToken":[]},{"nip98StepUp":[]}],"responses":{"200":{"description":"New token (the old one stops working)"}}}},"/v1/domains/{domain}/glue/{host}":{"parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string"}},{"name":"host","in":"path","required":true,"schema":{"type":"string"},"description":"a host under the domain, e.g. ns1.example.com"}],"put":{"tags":["domains"],"summary":"Glue addresses for the domain's own nameservers","security":[{"domainToken":[]},{"nip98":[]},{"session":[]},{"apiKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["ips"],"properties":{"ips":{"type":"array","minItems":1,"maxItems":13,"items":{"type":"string"}}}}}}},"responses":{"200":{"description":"OK"},"400":{"$ref":"#/components/responses/Error"}}}},"/v1/abuse/reports":{"post":{"tags":["free"],"summary":"Report abuse of a name served or sold here (no account)","description":"Reports are answered within 5 business days; phishing and malware evidence is acted on sooner. At most 5 reports an hour per client address, 10 per client network (IPv4 /24, IPv6 /48) and 30 in total (429; write to the abuse address instead). A name not served or sold here now (never ours, or a zone or hostname since removed, a domain transferred away or deleted) gets 404 not_ours.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AbuseReport"}}}},"responses":{"202":{"description":"Recorded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AbuseAck"}}}},"400":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/RateLimited"}}}}}}
