Authentication

All requests to /api/v1/* require a valid API key sent as a bearer token, except the two public endpoints — GET /verify/:code and GET /openapi.json:

Authorization: Bearer certify_live_...

A key is necessary, not sufficient

API access is entitlement-gated on top of the key. Every authenticated request re-checks that the owning account is on the Business plan or holds an active partner contract. A perfectly valid key on an account that has since downgraded or whose partner contract lapsed returns:

{
  "error": {
    "code": "forbidden",
    "message": "API access requires a Business plan. Upgrade to connect Certify+ to your own systems."
  }
}

This is a 403 with code forbidden — distinct from insufficient_scope, which means the key itself is missing a scope. If your integration starts returning 403 without a code change on your side, check the plan before you check the key.

Key format

Keys are prefixed with certify_live_ followed by 32 alphanumeric characters. Only the prefix plus the first 8 characters are shown back to you in the dashboard — the full key is only visible once at creation time.

Scopes

Each key is issued with one or more scopes. Requests outside a key's scopes return 403 insufficient_scope.

| Scope | Grants | |---|---| | templates:read | GET /templates, GET /templates/:id | | certificates:read | GET /certificates, GET /certificates/:id, GET /certificates/:id/pdf, GET /certificates/:id/emails, GET /usage | | certificates:write | POST /certificates, POST /certificates/:id/revoke, POST /certificates/:id/send |

GET /verify/:code requires no scope and no key.

Calling from a browser

Server-to-server is the intended shape — see the security notes below. For partner dashboards that must call the API from browser JavaScript, /api/v1/* responses carry CORS headers, but only for allowlisted origins. Requests from any other origin get no Access-Control-Allow-Origin and the browser blocks the response.

  • Allowlisted today: *.cybernestsolution.com, *.eneda-ph.com (apex included), and http://localhost:<port> for local development.
  • Preflight OPTIONS requests are answered with 204.
  • Permitted methods are GET, POST, OPTIONS; permitted request headers are Authorization and Content-Type.

To have an origin added, reach out via contact.

Rotation

Keys have no expiry. To rotate:

  1. Create a new key with the same scopes.
  2. Deploy the new key to your integration.
  3. Once traffic has shifted, revoke the old key in Settings → API Keys.

Revoked keys stop working immediately — there is no grace period.

Security

  • Never commit keys to source control. Use environment variables or a secret manager.
  • Never ship keys to the browser. Keys act on your behalf — anyone holding one can issue certificates against your quota. The CORS allowlist exists for partner dashboards that proxy through their own backend or scope keys tightly; it is not a licence to embed a write-scoped key in client-side JavaScript.
  • Scope aggressively. If an integration only reads, issue a key with just :read scopes.
  • Monitor usage. last_used_at updates on every request; surprising activity is a rotation signal.