Skip to content

Using the REST API

Tommi Grönlund edited this page Oct 23, 2026 · 2 revisions

Documentation for the image tag 1.0.0-rc1. See Versions for the documentation of a release.

Using the REST API

Everything the web UI and qca do goes through the REST API of the apiservice, by default on port 8082. All routes are under /v1, for example http://<QERTUM_HOST>:8082/v1/certificate-requests. Requests and responses are JSON.

The interactive OpenAPI page is only available on development builds, so this page is the reference for a deployed system.

Getting a token

The API accepts a bearer token (a JWT) issued by your identity provider and validated locally against its published keys. Qertum does not issue API tokens itself.

Caller How it gets a token
A person Signs in through the web UI, or uses qca auth login (device authorization flow)
A script or another system The OAuth client credentials grant with a client defined in your identity provider

With the built-in identity provider, the token endpoint is http://<QERTUM_HOST>:8081/connect/token. An automation client is an entry in its clients.json with the client_credentials grant and the roles its tokens should carry; edit the file on the identity volume and restart the identity service. With another OpenID Connect provider, create a client there. Details and per-provider notes are in the identity provider documentation shipped with the release.

TOKEN=$(curl -s -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=client_credentials -d scope=qertum-api \
  http://qertum.example.org:8081/connect/token | jq -r .access_token)

curl -s -H "Authorization: Bearer $TOKEN" http://qertum.example.org:8082/v1/me/access

Keep token lifetimes short. A token that was revoked stays valid until it expires. A machine token carries no interactive sign-in, so it is refused for operations that require step-up authentication unless your identity provider stamps the required claims.

Conventions

  • Authorization. Each route needs a permission (see Using the Web UI). Without it you get 403; without a valid token, 401.
  • Errors are application/problem+json: title is the category, detail the reason, traceId the correlation id. The same id is in the X-Correlation-Id response header on every response, so quote it when you report a problem.
  • Paging. List routes take page (from 1) and pageSize, and return { items, totalCount, page, ... }.
  • Rate limit. Routes under /v1/certificate-requests are limited per caller (100 requests per 60 seconds by default); excess requests get 429.
  • Asynchronous work. Approving and revoking return immediately; issuance and revocation finish in the background. While a request is in progress, responses carry Retry-After: 2; poll GET /v1/certificate-requests/{id} until the status is final (Issued, Rejected or Revoked).
  • Private keys are never part of a response body. Only the two key download routes below return a key, and each is audited.
  • IDs are GUIDs.

Request, approve, download

API=http://qertum.example.org:8082/v1
H="Authorization: Bearer $TOKEN"

# 1. file a request: it is created Pending
ID=$(curl -s -H "$H" -H 'Content-Type: application/json' -d '{
  "commonName": "www.example.com",
  "type": "WebServer",
  "keyAlgorithm": "ECDSA-P256",
  "validityDays": 90,
  "propertiesJson": "{\"dnsNames\":[\"www.example.com\"]}"
}' $API/certificate-requests | jq -r .id)

# 2. approve it (needs certificates.manage)
curl -s -X POST -H "$H" $API/certificate-requests/$ID/approve

# 3. wait until issued
until [ "$(curl -s -H "$H" $API/certificate-requests/$ID | jq -r .status)" = Issued ]; do sleep 2; done

# 4. download the certificate
curl -s -H "$H" "$API/certificate-requests/$ID/certificate?format=pem" -o www.example.com.pem

# revoke later
curl -s -X POST -H "$H" -H 'Content-Type: application/json' -d '{"reason":"key compromise"}' \
  $API/certificate-requests/$ID/revoke

To ask whether policy would accept a request without creating it, POST /v1/certificate-requests/preview takes the same body. The requester is always taken from your token; any name in the body is ignored.

Routes

P: shows the permission needed. "Signed in" means any valid token; "admin" means the admin role.

Certificates

Route P: Purpose
GET /v1/certificate-requests view List requests (paged)
GET /v1/certificate-requests/status-counts view Counts by status
GET /v1/certificate-requests/summary view Summary figures
GET /v1/certificate-requests/issued view Issued certificates
GET /v1/certificate-requests/issued/validity-counts view Issued, grouped by remaining validity
GET /v1/certificate-requests/rejected view Rejected requests
GET /v1/certificate-requests/revoked view Revoked certificates
GET /v1/certificate-requests/expired view Expired certificates
GET /v1/certificate-requests/{id} view One request
GET /v1/certificate-requests/{id}/timeline view Lifecycle history
POST /v1/certificate-requests create File a request (starts Pending)
POST /v1/certificate-requests/preview create Check a request against policy
PUT /v1/certificate-requests/{id} manage Edit a request
DELETE /v1/certificate-requests/{id} manage Delete a request
POST /v1/certificate-requests/{id}/approve manage Approve
GET /v1/certificate-requests/{id}/approval-preview manage Would approval pass policy
POST /v1/certificate-requests/{id}/reject manage Reject
POST /v1/certificate-requests/{id}/revoke manage Revoke, body { "reason": ... }
POST /v1/certificate-requests/{id}/renew create Renew
PUT /v1/certificate-requests/{id}/metadata owner or manage Set owner team, contact, purpose and so on
GET /v1/certificate-requests/{id}/certificate view Download certificate, `format=pem
GET /v1/certificate-requests/{id}/private-key owner or admin Download the key (audited, may need step-up)
POST /v1/certificate-requests/{id}/pfx owner or admin Download a password-protected PFX (audited, may need step-up)
POST /v1/certificate-requests/{id}/notes view Add a note
PUT /v1/certificate-requests/{id}/notes/{noteId} author Edit a note
DELETE /v1/certificate-requests/{id}/notes/{noteId} author Delete a note
GET /v1/certificate-inventory view Every issued certificate with its real key, signature, chain status and expiry
GET /v1/notices view Expiry and stalled-renewal notices
GET /v1/pqc/migration-report view Post-quantum migration report
GET /v1/dashboard/attention signed in What needs attention
GET /v1/me/access signed in Your roles and permissions
GET /v1/enrollment/options create Enrollment options

Templates and policies

Route P: Purpose
GET /v1/certificate-templates view List templates
GET /v1/certificate-templates/{id} view One template
POST /v1/certificate-templates settings Create
PUT /v1/certificate-templates/{id} settings Update
DELETE /v1/certificate-templates/{id} settings Delete
PUT /v1/certificate-templates/{id}/issuance-policy policies.publish Link a policy
PUT /v1/certificate-templates/{id}/issuer settings Choose the issuer
PUT /v1/certificate-templates/{id}/pqc-stage admin Set the post-quantum stage for one template
GET /v1/issuance-policies view List policies
GET /v1/issuance-policies/{id} view One policy
GET /v1/issuance-policies/{id}/versions view Versions
POST /v1/issuance-policies settings Create
PUT /v1/issuance-policies/{id} settings Rename
PUT /v1/issuance-policies/{id}/draft settings Replace the draft rules
DELETE /v1/issuance-policies/{id}/draft settings Discard the draft
POST /v1/issuance-policies/{id}/publish policies.publish Enforce the draft
POST /v1/issuance-policies/{id}/archive settings Archive
POST /v1/issuance-policies/{id}/unarchive settings Unarchive
DELETE /v1/issuance-policies/{id} settings Delete
GET /v1/pqc-exceptions admin List exceptions
POST /v1/pqc-exceptions admin Grant an exception
POST /v1/pqc-exceptions/{id}/revoke admin End an exception

CA and issuers

Route P: Purpose
GET /v1/ca/status signed in CA state
GET /v1/ca/certificate signed in The CA certificate
POST /v1/ca/generate settings Generate a root CA
POST /v1/ca/import settings Import a CA
GET /v1/issuers view List issuers
GET /v1/issuers/{id} view One issuer
GET /v1/issuers/{id}/certificate none Issuer certificate, format=der for DER
GET /v1/issuers/{id}/chain none Chain to the root
GET /v1/issuers/trust-bundle none Roots of every active or retired issuer
POST /v1/issuers/intermediates admin Create an intermediate
GET /v1/issuers/{id}/request admin Request file of a pending intermediate
POST /v1/issuers/{id}/certificate admin Install the signed certificate
POST /v1/issuers/{id}/crl admin Upload an offline issuer's CRL
POST /v1/issuers/{id}/make-default admin Make the default issuer
POST /v1/issuers/{id}/retire admin Stop signing
POST /v1/issuers/{id}/archive admin Archive
DELETE /v1/issuers/{id} admin Abandon a pending intermediate
GET /v1/issuers/{id}/private-key admin Export the CA key (audited, step-up)
POST /v1/issuers/{id}/pfx admin Export a CA PFX (audited, step-up)
POST /v1/crl/reset-base settings Reset the CRL base

Operations and administration

Route P: Purpose
POST /v1/bulk-operations/preview by kind Preview a bulk revoke or renew
POST /v1/bulk-operations/{id}/execute by kind Run a previewed operation
POST /v1/bulk-operations/{id}/cancel by kind Cancel a preview
GET /v1/bulk-operations signed in List bulk operations
GET /v1/bulk-operations/{id} signed in One operation
GET /v1/bulk-operations/{id}/items signed in Its items
GET /v1/settings settings CA settings
PUT /v1/settings settings Change settings
PUT /v1/settings/pqc-stage admin Post-quantum enforcement stage
PUT /v1/settings/ca-approval admin Who approves CA-capable requests
PUT /v1/settings/issuer-strength admin Off, Warn or Enforce: a key may not claim a higher post-quantum level than its issuer
PUT /v1/settings/two-person-approval admin Switch two-person approval
POST /v1/approvals signed in Ask a second administrator to approve
POST /v1/approvals/{id}/approve signed in Approve (a different administrator than the requester)
POST /v1/approvals/{id}/deny signed in Deny (an administrator)
GET /v1/approvals signed in List approvals
GET /v1/permissions admin Role permissions
PUT /v1/permissions/{role} admin Replace a role's permissions
GET /v1/webhooks settings List subscriptions
POST /v1/webhooks settings Create
PUT /v1/webhooks/{id} settings Update
DELETE /v1/webhooks/{id} settings Delete
GET /v1/webhook-destinations admin Allowed destinations
GET /v1/acme/orders settings ACME orders
GET /v1/acme/external-account-keys settings ACME external account bindings
POST /v1/acme/external-account-keys settings Create one (the key is shown once)
GET /v1/est/enrollment-credentials settings EST credentials
POST /v1/est/enrollment-credentials settings Create one (the password is shown once)
GET /v1/audit-log admin Audit log, newest first
GET /v1/audit-log/checkpoint admin Head of each audit hash chain

Some groups have more routes than listed here (editing and deleting ACME and EST credentials, webhook destination rules, bulk operation details). The qca <group> --help output of the release you run lists the matching commands, and each calls exactly one of these routes.

Certificate revocation and status

The CRL and OCSP responder follow their own protocol formats rather than the JSON conventions above. Point relying parties at /v1/crl and /v1/ocsp on the API port, or at the CRL and OCSP URLs embedded in the certificates themselves. ACME is served under /acme/ on its own port and EST under /.well-known/est/; see Architecture.

See also

Clone this wiki locally