Domains and TLS
Attach hostnames, verify DNS, and manage certificates.
Domains connect hostnames to a project and track DNS verification and TLS certificates. The SDK takes a project ID as the first argument when creating or listing domains; REST includes it in the body or query.
Add a domain
const result = await ship.domains.create("proj_123", {
hostname: "app.example.com",
});
console.log(result);curl -X POST "$SYNQ_URL/api/domains" \
-H "Authorization: Bearer $SYNQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{"projectId":"proj_123","hostname":"app.example.com"}'Prop
Type
Adding a domain doesn't make it live by itself
After adding, you must point your DNS at Synq and then verify. Use POST /api/domains/preview
(or synq domain preview <hostname>) to see the exact records to add at your DNS provider first.
Preview required DNS
Side-effect-free: pass a hostname, get back the records to create. POST is used only so the hostname
travels in the body.
const result = await ship.domains.preview({
hostname: "app.example.com",
});
console.log(result);curl -X POST "$SYNQ_URL/api/domains/preview" \
-H "Authorization: Bearer $SYNQ_TOKEN" \
-H "Content-Type: application/json" \
-d '{"hostname":"app.example.com"}'The response's mode tells you which setup applies: selfhosted (an A record to your server), cloud
(a CNAME to a hosted cloud; switched off in Synq), or external (a TXT record only; you front TLS yourself).
Verify a domain
const verification = await ship.domains.verify("dom_123");
console.log(verification);curl -X POST "$SYNQ_URL/api/domains/dom_123/verify" \
-H "Authorization: Bearer $SYNQ_TOKEN"Once DNS is in place, verify it. Synq checks the routing record and the ownership TXT record, marks the domain active, and (unless it's external-ingress) provisions SSL in the background.
Errors
422 — verification failed
The DNS records aren't resolving yet, or don't match. DNS can take minutes to hours to propagate. Confirm
the records match preview exactly, then retry. The response's cnameVerified / txtVerified flags tell
you which check is still failing.
404 on a per-domain route
The :id doesn't belong to your organization (or was deleted). List your domains with GET /api/domains
to get valid IDs.
Operations
| Operation | SDK | REST API |
|---|---|---|
| Stream domain verification progress. | domains.verifyStream(id, input?, options?) | POST /api/domains/:id/verify/streamdomain:write |
| List domains using the supplied filters. | domains.list(id) | GET /api/domainsdomain:list |
| Attach a domain using the requested project and routing configuration. | domains.create(id, input) | POST /api/domainsdomain:write |
| Read one domain record. | domains.get(id) | GET /api/domains/:iddomain:read |
| Remove a domain and its routing binding. | domains.remove(id) | DELETE /api/domains/:iddomain:admin |
| Run domain verification. | domains.verify(id, input?) | POST /api/domains/:id/verifydomain:write |
| Read whether the domain is routed through the server's Cloudflare Tunnel. | domains.tunnelRoute(id) | GET /api/domains/:id/cloudflare-tunneldomain:read · Self-hosted |
| Route the domain through the server's Cloudflare Tunnel, or stop routing it (optionally deleting its DNS record). | domains.setTunnelRoute(id, input) | PUT /api/domains/:id/cloudflare-tunneldomain:write · Self-hosted |
| Read DNS records required by a domain. | domains.records(id, input?) | GET /api/domains/:id/recordsdomain:read |
| Preview DNS changes before applying them. | domains.dnsPlan(id, input?) | GET /api/domains/:id/dns/plandomain:read |
| Apply the authorized DNS plan. | domains.dnsApply(id, input?) | POST /api/domains/:id/dns/applydomain:write |
| Select the project’s primary domain. | domains.setPrimary(id) | POST /api/domains/:id/primarydomain:write |
| Request certificate renewal for a domain record. | domains.renewSsl(id) | POST /api/domains/:id/renewdomain:write |
| Check the domain’s current certificate. | domains.verifySsl(id) | POST /api/domains/:id/verify-ssldomain:write |
| Install a supplied certificate and private key. | domains.uploadCert(id, input) | POST /api/domains/:id/certificatedomain:write · Self-hosted |
| Read a domain's custom OpenResty directives and its rendered vhost. | domains.customConfig(id) | GET /api/domains/:id/custom-configdomain:read · Self-hosted |
| Replace a domain's custom OpenResty directives (organization admins, self-hosted). | domains.setCustomConfig(id, input) | PUT /api/domains/:id/custom-configdomain:admin · Self-hosted |
| Read a domain's path routes: path prefixes served by another service, possibly of another project on the same server. | domains.pathRoutes(id) | GET /api/domains/:id/path-routesdomain:read · Self-hosted |
| Replace a domain's path routes (self-hosted); the edge applies them with automatic rollback. | domains.setPathRoutes(id, input) | PUT /api/domains/:id/path-routesdomain:write · Self-hosted |
| Show how a server's edge routes each hostname and path, in nginx match order, with the service each rule reaches. | domains.edgeRouting(input?) | GET /api/edge/routingserver:read · Self-hosted |
| Preview domain connection requirements. | domains.preview(input) | POST /api/domains/previewdomain:read |
| Request renewal for eligible certificates. | domains.renewAllSsl() | POST /api/domains/renew-alldomain:write |
| Verify pending domains visible to the caller. | domains.verifyPending(input?) | POST /api/domains/verify-pendingdomain:write |
| List every domain across the caller's projects with certificate state and the renewal schedule. | domains.overview() | GET /api/domains/overviewdomain:list |
| Check live DNS for a hostname against the record it needs. | domains.dnsCheck(input) | POST /api/domains/dns-checkdomain:read |
| Read the certificate authority settings used for automatic HTTPS. | domains.acmeSettings() | GET /api/domains/acmedomain:read · Self-hosted |
| Set or clear the Let's Encrypt contact email that overrides SYNQ_ACME_EMAIL. | domains.updateAcmeEmail(input) | PUT /api/domains/acme/emaildomain:admin · Self-hosted |