REST API overview¶
Everything the dashboard does is available under /api/v1, and the Agent,
the plugins and the reporting scripts use the same API. This page covers the
conventions that apply to every call; the interactive reference lists each
route.
Where the API lives¶
| Host | Serves | Typical caller |
|---|---|---|
Your workspace address - https://<slug>.app.certin.tel or your own vanity domain - plus /api/v1 |
The whole API and the dashboard. | Browser sessions, integration keys, scripts that read the inventory. |
The ingest host https://api.certin.tel |
Only the routes an Agent or reporting script needs: POST /api/v1/renewals, /checkins, /internal-certs, /agents/heartbeat, /agents/capabilities, /agents/workflow-assignments and …/{id}/status, /agents/unregister, /internal-endpoints/claim and …/{id}/result, /crl-monitors/report, /private-cas/{id}/issue, the …/agent/all listings, /install-tokens/exchange, /dns-delegations/{id}/txt, /acme-dns/update, /api/v1/auth/me, /api/v1/releases, /api/v1/meta, /api/v1/version and the public /pki/ publication paths. No dashboard, no sign-in, no inventory reads. |
Agents, ACME clients and scanners that must keep working even when the dashboard sits behind an IP allowlist. |
The ingest host is never filtered by the workspace IP allowlist; the workspace address is, unless Settings → Security allows ingest from any IP. Use the exact base URL shown on the Install Tokens, API Keys or Delegated DNS-01 page rather than deriving one.
Interactive reference¶
Sign in to your workspace and open API docs from the account menu, or go
to /api/v1/docs (Swagger UI) or /api/v1/redoc; the schema is at
/api/v1/openapi.json. The reference is generated from the running platform,
so it always matches the deployed version. Demo accounts are redirected away
from it. GET /api/v1/meta (no authentication) returns the product version,
build, deployment mode and capability flags; GET /api/v1/version adds the
database schema status.
Authentication¶
- API keys are presented as
<prefix>.<secret>in either theX-Api-Keyheader orAuthorization: Bearer <prefix>.<secret>. What a key may do is decided by its kind, its API role and its organization binding; see API keys & authentication. A wrong, revoked or expired key always gets the same401. A read-only key (the API read-only role, or a custom API role that holds only read permissions) may only send GET requests under/api/v1; anything else answers403. - Browser sessions from the dashboard can call the API too (the API docs
page relies on this).
POST /api/v1/auth/loginstarts a session for a local account and is throttled like the sign-in page (10 attempts per minute per address and email, 30 per address, and a 15-minute lockout after eight consecutive failures); a spent limit answers429withRetry-After. Single sign-on users sign in through the dashboard. POST /api/v1/auth/change-passwordrefuses a new password equal to the current one (400). Wrong current passwords have their own limit (eight per account in 15 minutes, then429withRetry-After) and do not count toward the sign-in lockout. For an account with two-factor sign-in, the answer hasmfa_required: trueand the session can only callPOST /api/v1/auth/mfa/verify(withcodeorrecovery_code),GET /api/v1/auth/meandPOST /api/v1/auth/logoutuntil the code is verified; every other call answers403withmfa-required.GET /api/v1/auth/medescribes the current principal: the tenant, the organizations it can act in, its permissions, and for a reporting key thereporting_organization_idits submissions land in. It is the quickest way to check a new key.
Pagination¶
List routes use keyset pagination:
| Query parameter | Meaning |
|---|---|
limit |
Rows per page, 1–200, default 50. |
cursor |
The opaque meta.next_cursor from the previous page; omit for the first page. It is signed - do not construct or decode it. |
order |
asc or desc (default desc). |
Responses carry the rows in items and a meta object with limit,
next_cursor and has_more; stop when has_more is false. A list refuses
a query parameter it does not take with 422 (Unknown query parameter; this
list takes: …) instead of answering an unfiltered list; there is no sort
parameter. The interactive reference lists each route's filters.
Errors¶
Every error is an RFC 9457 problem document with
Content-Type: application/problem+json:
{
"type": "https://certin.tel/problems/not-found",
"title": "Not Found",
"status": 404,
"detail": "…",
"request_id": "…",
"errors": [{"field": "…", "message": "…"}]
}
errors appears only on validation failures (422). Text containing the NUL
character (U+0000) or an unpaired UTF-16 surrogate - in the path, a query
parameter, a JSON body or a form field - is refused before any route runs
with a 422 whose error has "type": "invalid_character" and names the
field (Text cannot contain the NUL character (U+0000) or an unpaired UTF-16
surrogate.). Quote the request_id when you report a problem; every 5xx
answer carries one, in the body and the X-Request-Id header. A resource that exists in another tenant or
organization answers 404, never 403, so an id cannot reveal what exists
elsewhere; see troubleshooting.
When a workspace accepts agents only on its own address (Only accept agent
submissions on our workspace address under Settings → Security), an
agent route called with that workspace's credential on any other address, such
as the shared ingest host, answers 404 with the type
…/problems/workspace-address-required and a detail naming the workspace
address: This workspace accepts agents only on its own address, https://….
Enrol the agent again with that address, or turn off "Only accept agent
submissions on our workspace address" on the workspace's Security page. Only
a caller that already authenticated as that workspace gets this answer; see
troubleshooting.
A 429 (…/problems/rate-limited) carries a Retry-After header: the
seconds left in the limit's window, rounded up (at least 1, never more than the
window). Wait that long before retrying; a request sent after exactly that wait
falls in the next window. Besides sign-in and ingest, the actions started by hand
that send or probe something are limited: a destination's test (3 per
destination and 10 per person a minute), a report's send and re-send (3 per
report and 10 per person an hour) and an endpoint's check (3 per endpoint and
30 per person a minute). The person's limit is counted first and the detail
says which limit refused the request; see
Alerts & notifications.
Resource families¶
| Prefix | What it covers | Guide |
|---|---|---|
/auth |
Session login/logout, password change, me, and the second sign-in step POST /auth/mfa/verify. |
this page, Two-factor sign-in |
/caa-check |
GET /api/v1/caa-check?name=<name>&name=<name>&ca=<key> (or directory=<ACME directory URL> instead of ca): whether each name's CAA records allow that CA to issue, with status allowed, refused (with fix and the record to add), check or not_applicable per name and a summary. CA keys: letsencrypt, zerossl, google, digicert, sectigo, sslcom, globalsign, actalis, amazon; an unknown directory is answered check. At most 20 names, 30 checks a minute per user or key (429 with Retry-After); needs targets.read, workflow_assignments.read or dns_delegations.read. |
CAA records |
/organizations, /users, /roles, /permissions |
Organization tree, users, built-in and custom roles, the permission catalogue (/roles and /permissions need roles.read workspace-wide, or users.read for user roles, or api_keys.create, api_keys.update or api_keys.admin for API roles). A role has a kind, user or api: POST /roles takes it (default user), GET /roles?kind=user or ?kind=api narrows the list, an API role carries key_count and keys (the keys that use it), and GET /permissions?kind=api returns what a custom API role may hold. POST /users/{user_id}/mfa/reset removes a user's two-factor sign-in (users.update, 204). |
Organizations, users & roles, API roles, Two-factor sign-in |
/api-keys, /install-tokens |
Integration and Agent keys, install tokens and the exchange route. POST /api-keys takes an optional role (the id or key of an API role; the scope then follows from the role), PATCH /api-keys/{id} with {"role": "…"} gives a key another API role, and a key reads back with role, role_id and role_name. POST /install-tokens/one-time mints a one-time token (expires_in_minutes 15, 60, 240 or 1440; the 201 answer carries the secret once, with Cache-Control: no-store); token responses include kind (organization / one_time) and used_at, and reveal, rotate and reactivate answer 409 for a one-time token. |
API keys, Install tokens |
/certificates, /ct-findings, /targets |
The inventory, Certificate Transparency findings, public endpoint monitors. A certificate carries renewal_schedule (planned renewal, basis, ARI window, deployment state) when its managing Agent reports one. A CT finding carries issued_by_certintel, in_inventory and new_name_set. GET/POST /targets/{target_id}/certificate-links and DELETE /targets/{target_id}/certificate-links/{link_id} list, add and remove an endpoint's links to managed certificates (targets.read / targets.update). A target carries a tls block (grade, reasons, versions, cipher, key exchange group, post-quantum badge, chain, assessment time) and a writable probe_legacy_tls, on a platform build that offers TLS grades. |
Certificates, TLS grade, CT Log Watch |
/trusted-cas |
Trust anchors and the ignore list (ignored.json is public). |
Trusted CAs |
/private-cas and /pki/{ca_id}/… |
Issuing CAs, issuance, export, revocation and the public CRL publication. Where offered: POST /private-cas/{ca_id}/rotate (Rotate now, private_ca.update, 202), auto_rotate on PATCH, and GET /private-cas/{ca_id}/trust (per-host root trust, private_ca.read). |
Private CA |
/renewals, /checkins, /internal-certs |
Reporting from ACME clients and scanners. A renewal read carries failure_output (a failed installation step and the redacted end of its output) and deployment_window_override when the Agent reported them. |
ACME check-ins & renewals, Internal certificate scanners |
/agents, /internal-endpoints, /adcs-templates, /crl-monitors |
Enrolled Agents, platform-assigned endpoint checks, AD CS template and CRL distribution point monitors. GET/POST /internal-endpoints/{id}/certificate-links and DELETE /internal-endpoints/{id}/certificate-links/{link_id} list, add and remove an internal endpoint's links to managed certificates (internal_endpoints.read / internal_endpoints.update). Where offered, GET /agents lists Agents with agent_version, config_locked, outdated, latest_version and (with agent_updates.read) the live update_request (agents.read, ?outdated=true), and POST /agents/{api_key_id}/sealing-key/approve approves the sealing key an Agent reported, the first one or a new one (platform_credentials.update, 204): the body {"key_id": "<16 hex>", "fingerprint": "<SHA-256, optional>"} names the key you checked (422 without key_id), and 409 sealing-key-changed means another key waits now and nothing was approved. |
Monitors & internal endpoints, CRL monitoring, Install tokens & the Agents page |
/agent-updates |
Update requests for Agents: GET lists them, POST with api_key_ids (up to 500) or all_outdated: true and an optional target_version creates them (201; Agents that cannot take one are listed as skipped), DELETE /agent-updates/{id} cancels a request the Agent has not received yet (agent_updates.read / .create / .delete). The device decides whether to install. |
Install tokens & the Agents page |
/platform-credentials |
Appliance credentials for remote deployment: GET (list, one), POST (201), PATCH (rename or replace the secret), DELETE (204). Secrets are write-only and never returned (platform_credentials.*). |
Platform credentials |
/msp/organizations |
MSP mode: per client organization, expiring, expired, renewal_failures_7d, served_mismatches (public and internal endpoints together), offline_agents and ct_new_name_sets (workspace-wide users, Enterprise msp). |
Organizations, users & roles |
/dns-delegations and /acme-dns/update |
Delegated DNS-01 records and TXT updates. A TXT value is at most 255 ASCII characters (native API 422, acme-dns 400); /acme-dns/register answers 403 on every host that serves /acme-dns/update. |
Delegated DNS-01 |
/workflows |
Certificate workflows from a bundled template, for one Agent or several: list, create, read, edit, offer to the next Agent, start a new round or send again, cancel and delete. See Workflows. workflow_assignments.* permissions. |
Workflow Assignments |
/workflow-assignments |
The proposals of a workflow, one per Agent it was offered to; every assignment has a workflow_id. POST creates a workflow for one Agent and answers with its assignment; GET lists with cursor pagination and shows the timeline; …/{id}/resend, …/{id}/cancel, DELETE for finished ones. See Workflow assignments. The Agent's own routes are PUT /agents/capabilities, GET /agents/workflow-assignments and POST /agents/workflow-assignments/{id}/status. workflow_assignments.* permissions. |
Workflow Assignments |
/notification-channels, /scheduled-reports, /alert-contacts |
Alert destinations (an email destination takes up to 50 contact_ids; PUT and PATCH keep what they do not send, secrets included; an organization's destination refuses auth.warning), periodic report emails, and alert contacts (GET/POST /alert-contacts, PATCH/DELETE /alert-contacts/{id}; alert_contacts.read / .update; reads say whether the address unsubscribed). |
Alerts & notifications |
/oidc/providers |
Identity providers for single sign-on. | OIDC / SSO overview |
/releases |
Public release records for the Agent and plugins. | Downloads |
/activity, /jobs |
The activity log and background jobs. | - |
POST /api/v1/notification-channels/destinations/{id}/send-digest sends an
alert destination everything that is open for it now, labelled as sent on
request (see Send digest now). The destination's
scheduled alerts and daily summary are not changed. It answers status sent,
failed or nothing_due (nothing was sent), with tier, items,
response_status and failure_class. It needs notifications.test and
certificates.read in the destination's whole scope, answers 409 for a
paused destination, and is limited like a test send (429 with
Retry-After).
POST /api/v1/targets takes hostname as a DNS name or IP address only; the
port goes in port. A URL is refused with 422, and the message names what to
send: hostname must be a DNS name or IP address such as example.com, without
https://, a port or a path (the port goes in port). For
https://www.example.com:8443/shop, send hostname www.example.com and port
8443. The dashboard's Add a site form takes a pasted URL itself (see
What to do first).
Workflows¶
A workflow is a certificate, the bundled template that installs it, and the
Agents allowed to run it: one (the server the certificate is for) or up to 20
of one organization, first preferred. It is what Workflow Assignments in
the dashboard lists and what New workflow
creates. Errors are problem documents; a workflow or an Agent key
outside the organizations the caller can act in answers 404.
| Method and path | Body | Permission in the workflow's organization |
|---|---|---|
GET /api/v1/workflows |
Query: limit, cursor, order, state, api_key_id |
workflow_assignments.read |
POST /api/v1/workflows (201) |
The proposal fields, name and api_key_ids |
workflow_assignments.create and agents.read |
GET /api/v1/workflows/{id} |
- | workflow_assignments.read |
PUT /api/v1/workflows/{id} |
As for create | workflow_assignments.update, workflow_assignments.create and agents.read |
POST /api/v1/workflows/{id}/next |
- | workflow_assignments.update |
POST /api/v1/workflows/{id}/restart |
Optional {"api_key_id": "…"} |
workflow_assignments.update |
POST /api/v1/workflows/{id}/cancel |
Optional {"remove_from_agent": true\|false} |
workflow_assignments.update |
DELETE /api/v1/workflows/{id} (204) |
Query: optional remove_from_agent=true\|false |
workflow_assignments.delete |
The built-in roles: Observer and Auditor read; Operator creates,
edits, moves and cancels; deleting needs Administrator. A read-only API key reaches the two
GET routes only.
The proposal fields are those the workflow form fills in:
| Field | Value |
|---|---|
template |
id and version of a bundled template the Agent reports. |
variables |
The template's settings. A credential setting is local or platform:<id> (needs platform_credentials.read), never a value. |
certificate |
id (see the certificate id rule), name, domains, key_type, auto_renew. A challenge other than {"type": "dns-01"} is refused with 422. For a Private CA issuer also validity_days, ip_addresses, an optional private_ca_profile, and empty domains with ip_addresses; an IP address in an ACME certificate's domains is 422. |
issuer |
{"kind": "private-ca", "ca_id": "…"} or {"kind": "acme", "account_id": "…"}. |
deployment_window |
Optional; see Deployment windows. |
dns_delegations |
ACME only: [{"domain": "…", "delegation_id": "…"}], the organization's Delegated DNS-01 records that validate the base domains. |
issue_now |
Boolean, default false. |
note |
Optional, at most 500 characters, shown to the person who approves on the device. |
expires_in_days |
1 to 90, default 30. |
name is optional, at most 120 characters; left out, the workflow takes the
certificate's name, or its id. api_key_ids lists 1 to 20 Agent keys of one
organization, first preferred; a key listed twice is 422. A field the Agent
does not report support for is refused with 422.
A workflow reads back with id, organization_id, name,
certificate_id, state, api_key_ids, the proposal fields,
bound_api_key_id (the Agent that runs it), offered_api_key_id and
current_assignment_id (the proposal that is out), round_started_at,
created_by, created_at and updated_at.
state |
Meaning |
|---|---|
offering |
It is being offered to an Agent. |
bound |
An Agent applied the workflow and runs it. |
exhausted |
No Agent took it: every one rejected it, failed it before applying it or let it expire. |
cancelled |
Cancelled. |
- List is paged like the other lists.
statefilters on one of the four states;api_key_idreturns the workflows that name that Agent. - Read one adds
agents,offersandtimeline. Each ofagentshasapi_key_id,name,position,status(offered,running,triedorwaiting) andproblem: why that Agent cannot take the workflow now, ornull.offersare the workflow's assignments, newest first. - Create offers the workflow to its first Agent as a
pendingassignment; nothing is applied by the call. With several Agents, every one must be able to run the workflow now, or the answer is422and names each one that cannot. With one Agent the refusal is that Agent's own:409when it has sent no capabilities report, its credential cannot take proposals or the certificate id is taken there;403for an issuer the key may not use;422for the proposal itself. -
Edit (
PUT) replaces the name, the Agents and the proposal. The certificate id cannot change (422). The answer addsoutcome:outcomeWhat happened savedStored; nothing was sent. resentThe proposal that is out was sent again with the edit. offeredThe workflow was offered afresh. exhaustedNo Agent can take it now. updateSent to the Agent that runs it, as a replacement it applies once approved there (Agent 1.8.2 or later). It is refused with
409while the Agent is applying the workflow, and for a cancelled workflow. - Next withdraws the proposal that is out and offers the workflow to the next Agent that can take it;409unless a proposal is waiting. When nobody is left, the state isexhausted. - Restart starts a new round with the first Agent that can take it, or sends the workflow to the Agent named inapi_key_id(404when that key is not one of the workflow's Agents,422when it cannot run the workflow now). This is how a proposal the Agent rejected is sent again. A workflow an Agent runs moves to another Agent; the Agent that ran it keeps its copy until a local administrator removes it there.409for a cancelled workflow. - Cancel withdraws the proposal that is out. An Agent that already runs the workflow is also asked to remove it (Agent 1.19.0+; see Removing a workflow from the Agent).remove_from_agentomitted: removed from each Agent that can take a removal; an older Agent keeps it until a local administrator removes it there.true:422Requires Agent 1.19.0 or later onwhen the Agent is older. false: the Agent keeps it. - Delete is refused with409while a proposal is out; a removal that is out does not block it.remove_from_agentworks as for Cancel. The workflow's assignments and activity events are kept. - A removal is listed among the workflow's assignments withrequest_typeretire; other assignments havecreateorreplace.
Workflow assignments¶
An assignment is one proposal of a workflow to one Agent. Every assignment
has workflow_id.
POST /api/v1/workflow-assignmentstakes the proposal fields and oneapi_key_id. It creates a workflow for that Agent, named after the certificate, and answers with its assignment.POST …/{id}/resendsends a waiting proposal again as a new revision. With a body (the proposal fields) it edits the workflow; the certificate id cannot change. A proposal the Agent rejected is not sent again here (409): restart its workflow withPOST /api/v1/workflows/{id}/restart.POST …/{id}/cancelwithdraws a waiting proposal. Its workflow goes to the next Agent, or is leftexhaustedwhen there is none.DELETE …/{id}removes a finished assignment. Its workflow stays.
Routes used only by the platform console are not part of the published schema.