Skip to content
Documentation

Reference

API reference

Request bodies, authentication requirements and response shapes for domain provisioning, certificate checks, verification links, API keys and signed webhooks.

Base URL and conventions

Send requests to https://api.autocertify.net using the paths below. JSON bodies use Content-Type: application/json. Successful calls return a resource, array or result object directly; 204 responses have no body. Resource IDs are UUIDs. Optional response fields are omitted when the underlying value is unavailable.

All response examples are illustrative data. Redacted DNS values, link tokens and secrets must be replaced by values returned for your own workspace. The quickstart captures real IDs and records for subsequent requests.

Authentication and authorization

Send Authorization: Bearer <token>. AutoCertify accepts active, unexpired ac_live_ API keys and Auth0 session ID tokens. The sign-in exchange returns the accepted ID token in token; its separate accessToken field is not the AutoCertify session bearer.

API-key scopes are exact grants: a write scope does not imply read access, and an empty scope list grants no protected API access. The following grants cover domain and certificate workflows:

API-key scopeAccess
domains:readRead/query domains, their DNS records, client records and session metadata.
domains:writeCreate/update/delete domains and clients.
certificates:readRead/query certificates and request bundle availability.
certificates:writeRequest issuance and refresh provider certificate status.
*All API-key-accessible operations, including credential metadata reads. Excludes owner/admin-only management actions.

Domain verification and recheck require both domains:write and certificates:write because they may issue or refresh a certificate. Creating or reminding a verification link requires the same two grants. Listing links requires those grants plus domains:read, because the returned URLs grant access to verification and issuance. Team and credential mutations, webhook registration, and billing checkout require an owner/admin human session; the wildcard API-key grant does not authorize those actions. Endpoint entries specify the required credential or scope.

Human sessions with the owner, admin or operator role can change domains, clients and certificates, and list, create or remind verification links. A read_only session can read domain, client and certificate records but cannot perform those writes or retrieve verification-link capabilities. Denied role checks return 403 forbidden.

Errors

The error envelope contains status, code, message and optional details. Validation failures return 400 validation_error with flattened formErrors and fieldErrors:

Validation error
{
  "status": 400,
  "code": "validation_error",
  "message": "Validation failed.",
  "details": {
    "formErrors": [],
    "fieldErrors": {
      "apex": [
        "Please enter a valid domain, like example.com"
      ]
    }
  }
}

Check HTTP status and code in your client. A verification operation can return 200 with DNS still pending or an issuance failure described in its result; inspect the operation’s state fields as well. An inaccessible workspace resource returns 404 not_found, and an invalid, revoked or expired API key returns 401 invalid_api_key. A key missing a required grant returns 403 insufficient_scope; an API key attempting owner/admin management or billing checkout returns 403 forbidden.

Rate limits

Defaults are per client IP in fixed 15-minute windows. Deployment configuration may change limits. Read RateLimit and RateLimit-Policy; on a 429 rate_limited response, wait for Retry-After before retrying.

Route groupDefault requests per window
/v1/* — shared admission before authentication600 across all API routes
/v1/auth/*20, within the shared API limit
/v1/public/signup20 in a separate bucket
/v1/public/verification-links/*60
/v1/verification-links/*60 in a separate bucket
/v1/site-scan/*120

Domain and certificate pagination

Domain and certificate query endpoints accept page.limit (integer 1–250, default 100) and an optional opaque page.cursor. Read items and the full matching total. When nextCursor is present, send it as page.cursor with the same filters and sort to retrieve the next page. Cursors are bound to the workspace, resource, filters and sort. Stop when nextCursor is absent. Invalid cursors return 400 invalid_cursor; invalid limits, filters or sort fields return 400 validation_error. Other list endpoints state their own limits.

POST /v1/domains/query — request
{
  "q": "example.com",
  "status": "active",
  "validationStatus": "verified",
  "page": {
    "limit": 50
  }
}
200 OK — one result, no further page
{
  "items": [
    {
      "id": "8a7260d9-4f3f-4cea-bc6f-60a1b87ddf10",
      "apex": "shop.example.com",
      "orgId": "47a33825-ea1f-469e-a984-7237de8e83ac",
      "contactEmail": "[email protected]",
      "createdAt": "2026-02-04T18:22:10.000Z",
      "updatedAt": "2026-02-04T18:43:07.000Z",
      "tags": [
        "storefront"
      ],
      "validation": {
        "status": "verified",
        "delegation": {
          "type": "CNAME",
          "host": "_acme-challenge.shop.example.com",
          "value": "<DCV target returned for your domain>",
          "ttl": 300
        },
        "ownership": {
          "type": "TXT",
          "host": "_autocertify-verify.shop.example.com",
          "value": "autocertify-domain-verification=<your ownership token>",
          "ttl": 300
        },
        "lastCheckedAt": "2026-02-04T18:41:52.000Z"
      },
      "cert": {
        "status": "active",
        "issuer": "Cloudflare for SaaS Managed CA",
        "notAfter": "2026-05-05T18:43:07.000Z",
        "nextRenewalAt": "2026-04-05T18:43:07.000Z",
        "lastIssuedAt": "2026-02-04T18:43:07.000Z",
        "traceId": "d938d38a-7b8c-4a1b-bd25-1e3ca6bf275d"
      },
      "opsStatus": "active"
    }
  ],
  "total": 1
}

Idempotent issuance

Certificate issuance accepts an Idempotency-Key of up to 200 characters. Generate it once per logical operation and keep the same key, method, path and request body when retrying. A completed request replays its stored result; an in-progress request returns 409 idempotency_in_progress. Reusing the key for a different body returns 409 idempotency_key_reused. Use a status refresh to get a newer provider result.

Request once, retain the same key for retries
# Generate once for this logical issuance request; retain the key for retries.
AUTOCERTIFY_IDEMPOTENCY_KEY="$(node -e 'process.stdout.write(require("node:crypto").randomUUID())')"

curl --fail-with-body \
  -X POST https://api.autocertify.net/v1/domains/$AUTOCERTIFY_DOMAIN_ID/certificates/issue \
  -H "Authorization: Bearer $AUTOCERTIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $AUTOCERTIFY_IDEMPOTENCY_KEY" \
  -d '{}'

Resource fields

Domain

  • id, apex, orgId, createdAt, updatedAt and tags identify and organize the domain.
  • clientId, contactEmail and notes are optional.
  • validation.status is pending, verified or error. validation.delegation and validation.ownership hold the required DNS records; lastCheckedAt and lastError may also be present inside validation.
  • cert.status is none, pending, active, renewing, error or blocked. Certificate summary fields can include issuer, notAfter, nextRenewalAt, lastIssuedAt, lastError and traceId.
  • opsStatus is active, action_needed, blocked or pending. This is the field matched by the domain query’s status filter.

Certificate

A certificate has id, domainId, apex, wildcard, issuer, status (pending, active or error), provider and bundleAvailable. Optional fields include notBefore, notAfter, provider IDs/statuses and lastCheckedAt. Cloudflare reports the issuer; the service uses Cloudflare for SaaS Managed CA when that information is unavailable.

notBefore records when AutoCertify first stores an active certificate state; notAfter is the expiry reported by Cloudflare. The separate Domain.cert.nextRenewalAt and issue/refresh summary field are calculated 30 days before expiry when available. They are planning timestamps, not scheduled renewal execution times. The Certificate GET object does not contain nextRenewalAt.

active means Cloudflare reported both the custom hostname and SSL certificate active at the last provider check. Verify the website’s actual HTTPS connection after traffic routing and origin configuration are in place. Managed private keys and PEM bundles are not available for download.

Sign-up and sessions

Account sign-up is passwordless. Complete the Auth0 sign-in flow to obtain an authenticated session.

POST /v1/public/signup Public

Provision a new email’s workspace and first domain. Body: email and domain. Do not send a password.

Authorization: No bearer required.

Request body
{
  "email": "[email protected]",
  "domain": "shop.example.com"
}
201 Created — new account
{
  "userEmail": "[email protected]",
  "domain": {
    "id": "8a7260d9-4f3f-4cea-bc6f-60a1b87ddf10",
    "apex": "shop.example.com",
    "orgId": "47a33825-ea1f-469e-a984-7237de8e83ac",
    "contactEmail": "[email protected]",
    "createdAt": "2026-02-04T18:22:10.000Z",
    "updatedAt": "2026-02-04T18:22:10.000Z",
    "tags": [],
    "validation": {
      "status": "pending",
      "delegation": {
        "type": "CNAME",
        "host": "_acme-challenge.shop.example.com",
        "value": "<DCV target returned for your domain>",
        "ttl": 300
      },
      "ownership": {
        "type": "TXT",
        "host": "_autocertify-verify.shop.example.com",
        "value": "autocertify-domain-verification=<your ownership token>",
        "ttl": 300
      }
    },
    "cert": {
      "status": "none"
    },
    "opsStatus": "action_needed"
  },
  "portalUrl": "https://app.autocertify.net/site/8a7260d9-4f3f-4cea-bc6f-60a1b87ddf10/dns",
  "authProvider": {
    "type": "oidc",
    "passwordless": true,
    "loginUrl": "https://app.autocertify.net/"
  }
}

For an existing email, returns 202 with userEmail, status: sign_in_required, message, portalUrl ending in /login, and authProvider {type: oidc, passwordless: true, loginUrl}. It creates no domain in the existing workspace. Sign in and call POST /v1/domains instead.

POST /v1/auth/oidc/exchange Public

Exchange the sign-in authorization code server-side. Body: code, codeVerifier (43–128 PKCE characters), and optional nonce. Returns token, accessToken, tokenType, expiresInSeconds and email.

Authorization: Valid authorization code and its PKCE verifier.

Use the returned token field, containing the verified ID token, as the AutoCertify bearer. Auth0 resource-server access tokens are not accepted as AutoCertify session credentials.

GET /v1/auth/session Public

Returns userEmail and org {id, name, createdAt} for an authenticated caller. With authentication required and no token, returns JSON null.

Authorization: Optional session bearer, or an API key with domains:read or '*'.

POST /v1/auth/logout Public

Returns 204 No Content. Clear stored application tokens and complete your identity-provider logout flow when signing out.

Authorization: No bearer required.

This endpoint is a compatibility acknowledgement and does not revoke an already-issued JWT or API key. Revoke automation keys through the API-key revocation endpoint.

Domains

Domain responses use validation, cert and opsStatus. DNS verification requires both the delegation CNAME and this workspace’s ownership TXT.

POST /v1/domains Bearer token

Create a hostname in your workspace. Required: apex. Optional: contactEmail, clientId (UUID), tags (string array), notes (up to 2,000 characters). Returns a Domain with both DNS records.

Authorization: Owner/admin/operator session or domains:write API key.

Request body
{
  "apex": "shop.example.com",
  "contactEmail": "[email protected]",
  "tags": [
    "storefront"
  ]
}
201 Created — Domain
{
  "id": "8a7260d9-4f3f-4cea-bc6f-60a1b87ddf10",
  "apex": "shop.example.com",
  "orgId": "47a33825-ea1f-469e-a984-7237de8e83ac",
  "contactEmail": "[email protected]",
  "createdAt": "2026-02-04T18:22:10.000Z",
  "updatedAt": "2026-02-04T18:22:10.000Z",
  "tags": [
    "storefront"
  ],
  "validation": {
    "status": "pending",
    "delegation": {
      "type": "CNAME",
      "host": "_acme-challenge.shop.example.com",
      "value": "<DCV target returned for your domain>",
      "ttl": 300
    },
    "ownership": {
      "type": "TXT",
      "host": "_autocertify-verify.shop.example.com",
      "value": "autocertify-domain-verification=<your ownership token>",
      "ttl": 300
    }
  },
  "cert": {
    "status": "none"
  },
  "opsStatus": "action_needed"
}

clientId must identify a client in your workspace; a missing or foreign client returns 404 not_found with message 'Client not found.'. Submitting a hostname already in your workspace returns its existing domain record and updates supplied contact email/notes and delegation data. It does not create a second record or reset its ownership token.

POST /v1/domains/bulk Bearer token

Body: apexList (1–500 strings), optional clientId and tags. Returns 200 with created (Domain array) and rejected (objects with apex and reason). Per-domain failures allow partial success.

Authorization: Owner/admin/operator session or domains:write API key.

Request body
{
  "apexList": [
    "shop.example.com",
    "www.example.com"
  ],
  "tags": [
    "storefront"
  ]
}

An optional clientId must identify a client in your workspace. A missing or foreign client rejects each hostname in rejected with reason 'Client not found.'; the bulk response remains 200.

POST /v1/domains/query Bearer token

Body: optional q, status, validationStatus, certStatus, clientId, tags, sort and page. status filters opsStatus (active, action_needed, blocked, pending); validationStatus accepts pending, verified or error. Returns items, total and nextCursor when another page exists.

Authorization: Session or domains:read API key.

certStatus accepts none, pending, active, renewing, error or blocked. clientId is a UUID. Every value in the tags array must match. sort accepts by (createdAt, updatedAt, apex, opsStatus, validationStatus or certStatus) and dir (asc or desc); the default is createdAt descending with a UUID tie-breaker.

GET /v1/domains/:domainId Bearer token

Read the saved Domain in your workspace. Unknown or inaccessible IDs return 404 not_found.

Authorization: Session or domains:read API key.

PATCH /v1/domains/:domainId Bearer token

Update tags (string array) and/or notes (string). Returns the updated Domain. An empty tags array clears tags; an empty notes string clears the text.

Authorization: Owner/admin/operator session or domains:write API key.

Request body
{
  "tags": [
    "storefront",
    "production"
  ],
  "notes": "Customer-facing shop"
}
DELETE /v1/domains/:domainId Bearer token

Delete the domain record from your AutoCertify workspace. Returns 204 No Content.

Authorization: Owner/admin/operator session or domains:write API key.

Deleting the local record does not revoke the managed certificate at Cloudflare or change your DNS. Coordinate provider and routing cleanup separately when retiring a hostname.

GET /v1/domains/:domainId/delegation-record Bearer token

Return top-level CNAME type, host, value and ttl, plus the ownership TXT object. Publish both returned records.

Authorization: Session or domains:read API key.

200 OK — required DNS records
{
  "type": "CNAME",
  "host": "_acme-challenge.shop.example.com",
  "value": "<DCV target returned for your domain>",
  "ttl": 300,
  "ownership": {
    "type": "TXT",
    "host": "_autocertify-verify.shop.example.com",
    "value": "autocertify-domain-verification=<your ownership token>",
    "ttl": 300
  }
}
POST /v1/domains/:domainId/verify-delegation Bearer token

No body required. Check both DNS records. When verified and the domain certificate is not active, start or check issuance. Returns status, checkedAt, message and an optional certificate summary.

Authorization: Owner/admin/operator session or both domains:write and certificates:write API-key scopes.

200 OK — example with issuance pending
{
  "status": "verified",
  "checkedAt": "2026-02-04T18:41:52.000Z",
  "message": "DNS records verified successfully. Certificate issuance is now being checked. Cloudflare issuance is pending: hostname=pending, ssl=pending_validation.",
  "certificate": {
    "certificateId": "49c1a8d4-146e-48fc-ac52-4952e1c10876",
    "status": "pending",
    "message": "Cloudflare issuance is pending: hostname=pending, ssl=pending_validation."
  }
}

DNS status verified does not guarantee certificate activation. The certificate summary can be omitted for an already-active domain or an issuance exception; inspect message and the domain’s cert status/error.

POST /v1/domains/:domainId/recheck Bearer token

Verify DNS and refresh the most recent eligible certificate from Cloudflare. Returns status (domain opsStatus), checkedAt and certStatus. This endpoint does not perform a live website HTTPS scan.

Authorization: Owner/admin/operator session or both domains:write and certificates:write API-key scopes.

200 OK
{
  "status": "active",
  "checkedAt": "2026-02-04T18:43:07.000Z",
  "certStatus": "active"
}

Certificates

Cloudflare manages the certificate and private key at its edge. AutoCertify records provider status and can refresh it on demand.

POST /v1/domains/:domainId/certificates/issue Bearer token

Request or retrieve issuance for a DNS-verified domain. Body is optional; use {} for the supported per-hostname flow. Accepts Idempotency-Key. Returns certificateId, status, message and optional nextRenewalAt.

Authorization: Owner/admin/operator session or certificates:write API key.

Request body
{}
200 OK — issuance summary
{
  "certificateId": "49c1a8d4-146e-48fc-ac52-4952e1c10876",
  "status": "pending",
  "message": "Cloudflare issuance is pending: hostname=pending, ssl=pending_validation."
}

Unverified domains return 409 delegation_not_verified. For a verified domain, wildcard: true returns the error below. ca and chain strings are accepted for adapter compatibility but do not override the provider’s certificate settings.

400 Bad Request — wildcard on a verified domain
{
  "status": 400,
  "code": "wildcard_not_supported_in_minimal_cloudflare_mode",
  "message": "Wildcard issuance is not enabled for AutoCertify minimal Cloudflare Custom Hostname onboarding. Submit the exact hostname instead."
}
POST /v1/domains/:domainId/issue Bearer token

Compatibility alias of /v1/domains/:domainId/certificates/issue, with the same body and result. Idempotency records are scoped to the requested path, so retain the same path when retrying.

Authorization: Owner/admin/operator session or certificates:write API key.

POST /v1/domains/:domainId/certificates/query Bearer token

Body: optional page {limit, cursor}. List a domain’s saved certificates, newest first. Returns items, full total and nextCursor when another page exists.

Authorization: Session or certificates:read API key.

Request body
{
  "page": {
    "limit": 50
  }
}
GET /v1/certificates/:certificateId Bearer token

Read a saved Certificate by UUID. This call does not contact Cloudflare; use refresh to update the saved provider status.

Authorization: Session or certificates:read API key.

200 OK — Certificate
{
  "id": "49c1a8d4-146e-48fc-ac52-4952e1c10876",
  "domainId": "8a7260d9-4f3f-4cea-bc6f-60a1b87ddf10",
  "apex": "shop.example.com",
  "wildcard": false,
  "issuer": "Cloudflare for SaaS Managed CA",
  "status": "active",
  "notBefore": "2026-02-04T18:43:07.000Z",
  "notAfter": "2026-05-05T18:43:07.000Z",
  "provider": "cloudflare_for_saas",
  "providerCertificateId": "452c15e3-4dc0-437c-bd8d-cc677dfdbe6d",
  "providerHostnameId": "cbbe84c7-9b66-4f3d-9bf0-2d2b0ba2cbd1",
  "providerSslId": "452c15e3-4dc0-437c-bd8d-cc677dfdbe6d",
  "providerStatus": "active",
  "providerHostnameStatus": "active",
  "bundleAvailable": false,
  "lastCheckedAt": "2026-02-04T18:43:07.000Z"
}
POST /v1/certificates/:certificateId/refresh Bearer token

Read current Cloudflare hostname/SSL status and update the saved certificate and domain. Returns an issuance-style summary; it does not force a renewal or alter provider settings.

Authorization: Owner/admin/operator session or certificates:write API key.

200 OK — refresh summary
{
  "certificateId": "49c1a8d4-146e-48fc-ac52-4952e1c10876",
  "status": "active",
  "nextRenewalAt": "2026-04-05T18:43:07.000Z",
  "message": "Cloudflare reports the custom hostname and SSL certificate are active."
}
GET /v1/certificates/:certificateId/bundle Bearer token

Managed certificates are not exportable. Returns 409 cert_not_yet_issued while pending/failed, or 409 managed_certificate_bundle_unavailable for an active Cloudflare-managed certificate.

Authorization: Session or certificates:read API key.

Unknown or inaccessible certificates return 404 not_found. Other records without exportable material return 409 certificate_bundle_unavailable.

409 Conflict — active managed certificate
{
  "status": 409,
  "code": "managed_certificate_bundle_unavailable",
  "message": "This is a Cloudflare for SaaS managed certificate. It is deployed at Cloudflare edge and cannot be exported as a PEM bundle."
}

A shareable URL lets a DNS administrator view both required records and verify that domain. Treat the link token as a credential for those actions.

Webhooks

New provider issuance results emit cert.issued, cert.issue_pending or cert.issue_failed. The webhook guide documents the exact payload, signature, retries and status-refresh limits.

Read the webhook receiver and signature guide.

GET /v1/webhooks Bearer token

Return an array of endpoint metadata: id, url, events, createdAt, status, and optional lastDeliveryAt/lastStatusCode. No signing secrets are returned.

Authorization: Session or '*' API key.

POST /v1/webhooks Bearer token

Register a publicly reachable HTTPS url and optional events string array. An empty array or '*' subscribes to all emitted events. Returns the one-time signing secret.

Authorization: Owner/admin session only.

Request body
{
  "url": "https://hooks.example.com/autocertify",
  "events": [
    "cert.issued",
    "cert.issue_pending",
    "cert.issue_failed"
  ]
}
201 Created
{
  "id": "629ed412-af82-4a2c-b8d8-313998a18c45",
  "url": "https://hooks.example.com/autocertify",
  "events": [
    "cert.issued",
    "cert.issue_pending",
    "cert.issue_failed"
  ],
  "createdAt": "2026-02-04T18:22:10.000Z",
  "status": "active",
  "secret": "<one-time signing secret; redacted>"
}
PATCH /v1/webhooks/:webhookId Bearer token

Update url, events and/or status (active or disabled). Returns endpoint metadata without the secret.

Authorization: Owner/admin session only.

Request body
{
  "status": "disabled"
}
DELETE /v1/webhooks/:webhookId Bearer token

Remove the endpoint and its queued delivery records. Returns 204 No Content.

Authorization: Owner/admin session only.

POST /v1/webhooks/:webhookId/rotate-secret Bearer token

Immediately replace the signing secret. Returns endpoint metadata and a new secret beginning with whsec_. Update the receiver before subsequent attempts arrive.

Authorization: Owner/admin session only.

API keys

Keys beginning with ac_live_ authenticate server-side automation to one workspace. Send the complete secret as a bearer and grant only the scopes your workflow needs.

GET /v1/api-keys Bearer token

Return an array of metadata: id, name, prefix, scopes, createdAt, status and optional lastUsedAt/expiresAt. No complete secrets are returned.

Authorization: Session or '*' API key.

POST /v1/api-keys Bearer token

Body: name, scopes array containing supported grants and optional expiresAt (ISO datetime). Unknown scope names are rejected. Omitted/empty scopes grant no protected API access. Returns metadata and the complete secret once.

Authorization: Owner/admin session only.

Request body
{
  "name": "Certificate automation",
  "scopes": [
    "domains:read",
    "domains:write",
    "certificates:read",
    "certificates:write"
  ]
}
201 Created
{
  "id": "71c4ff3f-a90c-438b-b605-4c38958605a3",
  "name": "Certificate automation",
  "prefix": "ac_live_…",
  "scopes": [
    "domains:read",
    "domains:write",
    "certificates:read",
    "certificates:write"
  ],
  "createdAt": "2026-02-04T18:22:10.000Z",
  "status": "active",
  "secret": "<one-time ac_live_ secret; redacted>"
}
POST /v1/api-keys/:apiKeyId/rotate Bearer token

Replace the stored secret and return metadata with the new secret. The old secret immediately stops authenticating. Scope grants, expiry and revocation status are preserved.

Authorization: Owner/admin session only.

Rotating a revoked or expired key does not reactivate it. Create a new active key when needed.

POST /v1/api-keys/:apiKeyId/revoke Bearer token

Mark the key revoked so subsequent requests fail authentication. Returns 204 No Content.

Authorization: Owner/admin session only.

Website HTTPS scan

Check the HTTPS connection to a publicly reachable hostname separately from its saved provider certificate status.

POST /v1/site-scan/https Public

Body: urlOrDomain string. Check the public hostname on TLS port 443. Returns input, normalizedHost, status (secure, not_secure or error) and details.

Authorization: Optional bearer; no API-key scope required.

Request body
{
  "urlOrDomain": "shop.example.com"
}
200 OK
{
  "input": "shop.example.com",
  "normalizedHost": "shop.example.com",
  "status": "secure",
  "details": {
    "httpsReachable": true,
    "certificateValid": true,
    "certificateExpiresAt": "2026-05-05T18:43:07.000Z",
    "chainOk": true
  }
}

Failures can include details.reason; the scan does not always return a chainOk or expiry field. Private/internal destinations are rejected. This is a TLS connection check, not a full page-content or mixed-content audit.