API reference
Custom domains
Your own domains on an app: add, check, redirect, remove; prove a whole zone once.
An app answers on https://<app>.rytiv.app from the start. A custom domain is added to an app, proven by a DNS record, pointed at Rytiv, and gets its certificate from Rytiv. The answer of every domain route carries the DNS records to set. A zone proven once (/v1/domains/zones) covers every name below it without a record of its own. See the guide Custom domains and TLS.
Endpoints
Section titled “Endpoints”POST /v1/apps/:name/domains: Adds a custom domain to the app and answers the DNS records to setGET /v1/apps/:name/domains: The app’s custom domains with their statusPOST /v1/apps/:name/domains/:domain/check: Checks the DNS records now instead of waiting for the next automatic checkPUT /v1/apps/:name/domains/:domain/redirect: Redirects this domain (308) to another hostname of the same app, or clears the redirect withto: nullDELETE /v1/apps/:name/domains/:domain: Removes the domain from the appPOST /v1/domains/zones: Claims a whole zone: proven once, every name below it is yours without a record of its ownGET /v1/domains/zones: Your zonesGET /v1/domains/zones/:zone: One zone with its status and the records to setPOST /v1/domains/zones/:zone/check: Checks the zone’s records nowDELETE /v1/domains/zones/:zone: Releases the zone
POST /v1/apps/:name/domains
Section titled “POST /v1/apps/:name/domains”Adds a custom domain to the app and answers the DNS records to set.
Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
name |
The app’s name. |
Request body
Section titled “Request body”JSON, the shape AddDomainRequest of the contract.
| Field | Type | Required | Description |
|---|---|---|---|
domain |
string | required | The domain, for example www.example.com. Wildcards are not accepted. 1 to 253 characters. |
Example request
Section titled “Example request”curl -X POST "https://api.rytiv.app/v1/apps/<name>/domains" \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"domain":"www.example.com"}'Response
Section titled “Response”201 with a JSON body.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 400 | bad-request |
The request is malformed or a field is out of range. error names every field; issues lists them. |
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
| 409 | mail-domain |
The name is a sending domain and cannot become an app domain. |
| 409 | shadows-default-address |
The domain is the default address of an app and cannot be a custom domain. |
GET /v1/apps/:name/domains
Section titled “GET /v1/apps/:name/domains”The app’s custom domains with their status.
Auth: API key with full access or the scope read. Every class of agent token may call it.
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
name |
The app’s name. |
Example request
Section titled “Example request”curl -X GET "https://api.rytiv.app/v1/apps/<name>/domains" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with a JSON body.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
POST /v1/apps/:name/domains/:domain/check
Section titled “POST /v1/apps/:name/domains/:domain/check”Checks the DNS records now instead of waiting for the next automatic check.
Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
name |
The app’s name. |
domain |
The domain, as added. |
Example request
Section titled “Example request”curl -X POST "https://api.rytiv.app/v1/apps/<name>/domains/<domain>/check" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with a JSON object carrying queued and the fields of the object the handler builds.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
PUT /v1/apps/:name/domains/:domain/redirect
Section titled “PUT /v1/apps/:name/domains/:domain/redirect”Redirects this domain (308) to another hostname of the same app, or clears the redirect with to: null.
Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
name |
The app’s name. |
domain |
The domain, as added. |
Request body
Section titled “Request body”JSON, the shape SetDomainRedirectRequest of the contract.
| Field | Type | Required | Description |
|---|---|---|---|
to |
string or null | required | Another hostname of the same app to redirect to, or null to clear the redirect. |
Example request
Section titled “Example request”curl -X PUT "https://api.rytiv.app/v1/apps/<name>/domains/<domain>/redirect" \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"to":"www.example.com"}'Response
Section titled “Response”200 with a JSON body.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 400 | bad-request |
The request is malformed or a field is out of range. error names every field; issues lists them. |
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
DELETE /v1/apps/:name/domains/:domain
Section titled “DELETE /v1/apps/:name/domains/:domain”Removes the domain from the app.
Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
name |
The app’s name. |
domain |
The domain, as added. |
Example request
Section titled “Example request”curl -X DELETE "https://api.rytiv.app/v1/apps/<name>/domains/<domain>" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”204 with no body.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
POST /v1/domains/zones
Section titled “POST /v1/domains/zones”Claims a whole zone: proven once, every name below it is yours without a record of its own.
Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).
Request body
Section titled “Request body”JSON, the shape AddZoneRequest of the contract.
| Field | Type | Required | Description |
|---|---|---|---|
zone |
string | required | The zone, for example example.com. 1 to 253 characters. |
Example request
Section titled “Example request”curl -X POST "https://api.rytiv.app/v1/domains/zones" \ -H "Authorization: Bearer $RYTIV_TOKEN" \ -H "Content-Type: application/json" \ -d '{"zone":"example.com"}'Response
Section titled “Response”200 or 201 with a JSON body.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 400 | bad-request |
The request is malformed or a field is out of range. error names every field; issues lists them. |
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 503 | zones-unavailable |
GET /v1/domains/zones
Section titled “GET /v1/domains/zones”Your zones.
Auth: API key with full access or the scope read. Every class of agent token may call it.
Example request
Section titled “Example request”curl -X GET "https://api.rytiv.app/v1/domains/zones" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with a list of zones, each:
[ { "zone": "example.com", "orgId": "<orgId>", "status": "pending_dns", "acmeLabel": "<acmeLabel>", "attempts": 0, "createdAt": "2026-10-21T09:00:00Z" }]| Field | Type | Present | Description |
|---|---|---|---|
zone |
string | always | The zone, for example example.com. |
orgId |
string | always | The organization that owns it. |
status |
pending_dns | verified | cert_issued | error |
always | |
error |
string or null | if set | |
acmeLabel |
string | always | |
certNotAfter |
string (ISO 8601) | if set | |
certIssuedAt |
string (ISO 8601) | if set | |
verifiedAt |
string (ISO 8601) | if set | |
lastCheckedAt |
string (ISO 8601) | if set | |
attempts |
integer | always | 0 to 9007199254740991, default 0. |
createdAt |
string (ISO 8601) | always | When it was created. |
dns |
object | if set | |
dns.acme |
object | always | |
dns.point |
object | always |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
GET /v1/domains/zones/:zone
Section titled “GET /v1/domains/zones/:zone”One zone with its status and the records to set.
Auth: API key with full access or the scope read. Every class of agent token may call it.
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
zone |
The zone, as claimed. |
Example request
Section titled “Example request”curl -X GET "https://api.rytiv.app/v1/domains/zones/<zone>" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with the zone:
{ "zone": "example.com", "orgId": "<orgId>", "status": "pending_dns", "acmeLabel": "<acmeLabel>", "attempts": 0, "createdAt": "2026-10-21T09:00:00Z"}| Field | Type | Present | Description |
|---|---|---|---|
zone |
string | always | The zone, for example example.com. |
orgId |
string | always | The organization that owns it. |
status |
pending_dns | verified | cert_issued | error |
always | |
error |
string or null | if set | |
acmeLabel |
string | always | |
certNotAfter |
string (ISO 8601) | if set | |
certIssuedAt |
string (ISO 8601) | if set | |
verifiedAt |
string (ISO 8601) | if set | |
lastCheckedAt |
string (ISO 8601) | if set | |
attempts |
integer | always | 0 to 9007199254740991, default 0. |
createdAt |
string (ISO 8601) | always | When it was created. |
dns |
object | if set | |
dns.acme |
object | always | |
dns.point |
object | always |
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
POST /v1/domains/zones/:zone/check
Section titled “POST /v1/domains/zones/:zone/check”Checks the zone’s records now.
Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
zone |
The zone, as claimed. |
Example request
Section titled “Example request”curl -X POST "https://api.rytiv.app/v1/domains/zones/<zone>/check" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”200 with a JSON object carrying queued and the fields of the object the handler builds.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
DELETE /v1/domains/zones/:zone
Section titled “DELETE /v1/domains/zones/:zone”Releases the zone.
Auth: API key with full access (a key with scopes cannot call this route). An agent token of class sandbox or twin may call it; class production is refused (agent-token-production-readonly).
Path parameters
Section titled “Path parameters”| Name | Description |
|---|---|
zone |
The zone, as claimed. |
Example request
Section titled “Example request”curl -X DELETE "https://api.rytiv.app/v1/domains/zones/<zone>" \ -H "Authorization: Bearer $RYTIV_TOKEN"Response
Section titled “Response”204 with no body.
Errors
Section titled “Errors”| Status | Code | Meaning |
|---|---|---|
| 401 | unauthenticated |
No API key, or one that does not work. |
| 403 | token-scope |
The key’s scopes do not cover this route. |
| 404 | not-found |
Not found, or not yours. An object of another organization answers like one that does not exist. |
| 409 | zone-in-use |