The Twins Proxy API

Everything the dashboard does — creating sites, provisioning masking domains, verifying DNS access, managing certificates — is available over a versioned REST interface. Requests and responses are JSON; the base path is /v1.

# List your domains
curl https://your-host/v1/domains \
  -H "Authorization: Bearer twp_live_…"

Authentication

Two credential types go in the Authorization: Bearer header: session tokens from login, and long-lived scoped API keys. Secrets are returned once on creation; the server stores only SHA-256 hashes.

POST/v1/auth/registerCreate an organization and its first user
POST/v1/auth/loginExchange email + password for a session (may return an MFA challenge)
POST/v1/auth/mfa/verifyComplete a two-factor challenge
POST/v1/auth/logoutRevoke the current session

Sites

A site is a reusable landing-page origin — a name and an HTTPS URL. Any number of masked domains may route to the same site.

GET/v1/sitesList origins
POST/v1/sitesCreate an origin
curl -X POST /v1/sites \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"name":"Acme landing","origin_url":"https://landing.acmemail.io"}'

Domains

Creating a domain starts the provisioning pipeline. With dns_method: "cloudflare" (default) validation records are written automatically; with dns_method: "manual" the API returns the TXT records to create at any DNS provider, and issuance starts once they are visible. Certificates cover the hostname and *.hostname. The proxy deploys once an origin is attached; the domain becomes active only after the edge answers HTTP 200.

GET/v1/domainsList domains with status and certificate stage
POST/v1/domainsProvision a hostname (requires a verified zone)
GET/v1/domains/{id}/eventsProvisioning event history
PATCH/v1/domains/{id}/proxyAttach an origin; optionally auto-manage DNS
POST/v1/domains/{id}/retryRetry a failed validation
POST/v1/domains/{id}/check-dnsRe-check manual TXT records immediately
POST/v1/domains/{id}/certificate/reissueReissue the certificate for a suspended domain
DELETE/v1/domains/{id}Suspend the proxy (certificate is kept)
DELETE/v1/domains/{id}/archiveArchive a suspended domain
curl -X POST /v1/domains \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"dns_connection_id":"…","dns_zone_id":"…",
      "domain":"go.acmemail.io"}'

DNS connections

A connection is a labeled Cloudflare account token (Zone Read + DNS Edit), encrypted at rest with AES-256-GCM. Zones are discovered automatically; write access is proven with a temporary TXT record removed after the check.

GET/v1/dns-connectionsList saved credentials
POST/v1/dns-connections/cloudflareSave and verify a token
PATCH/v1/dns-connections/{id}Rename a credential or rotate its token
POST/v1/dns-connections/{id}/verifyRevalidate the token and rediscover zones
GET/v1/dns-connections/{id}/zonesList accessible zones
POST/v1/dns-connections/{id}/zones/{zone}/verify-writeRun the TXT write check
DELETE/v1/dns-connections/{id}Delete a credential (dependent domains must be archived)

Certificates

Production certificates renew on a schedule well before expiry. Revocation is permanent and immediately suspends the domain’s proxy — prefer domain suspension for temporary downtime.

GET/v1/certificatesInventory with expiry and renewal dates
DELETE/v1/certificates/{id}Revoke permanently at the CA

API keys

Scopes follow resource:access — e.g. sites:read, domains:write. Grant the smallest set that works, and prefer an expiration.

GET/v1/api-keysList keys (prefixes only)
POST/v1/api-keysCreate a key — the secret appears once
DELETE/v1/api-keys/{id}Revoke a key

Billing

Plans: Free (1 domain), Basic (10 domains, $10/mo), Pro (25 domains, $20/mo), each with monthly bandwidth and request allowances. The domain limit is enforced at creation with HTTP 402.

GET/v1/billingPlan, limits, and this month's usage
POST/v1/billing/checkoutStart a Stripe Checkout for basic or pro

Errors

Failures return a conventional HTTP status and a JSON body with a stable machine-readable code and a human-readable message.

{ "error": { "code": "dns_write_not_verified",
    "message": "Verify DNS write access for the selected zone first" } }
401Missing, expired, or revoked credential
403Credential lacks the required scope, or MFA step-up is required
409Conflicting state — e.g. deleting a credential with dependent domains
429Rate limited — retry with backoff