API overview
Everything in the UI is available via the REST API. JSON
requests + responses, cursor-based pagination, deterministic
error shapes, per-route RBAC enforcement. 190+ endpoints under
/api/v1.
01Base URL
The same host as the UI, under /api/v1. Example: https://cap.example.com/api/v1. Everything that follows uses relative paths rooted there.
02Versioning
- Major version in the path (
/api/v1). A v2 would live at/api/v2alongside v1 during a transition window. - No breaking changes within a major. Additive changes only: new endpoints, new optional request fields, new response fields.
- When a breaking change is necessary, v2 opens for a deprecation window of ≥ 12 months, with
Deprecation+Sunsetheaders on v1 responses.
03Tenancy in the URL
Every project-scoped resource is under /projects/:projectId/...:
/api/v1/projects/{projectId}/certificates
/api/v1/projects/{projectId}/acme-accounts
/api/v1/projects/{projectId}/distributions
Org-scoped resources don't carry the project prefix:
/api/v1/users
/api/v1/audit-logs
/api/v1/ca-providers
There is no cross-project read endpoint. If you need cross-project data, iterate GET /projects and fan out.
04Content type
- Request:
Content-Type: application/jsonfor all mutations. The server rejects any other content type on POST/PUT/PATCH. - Response:
application/json, UTF-8. - One exception: file downloads (cert bundles, exports) return the appropriate
application/x-pem-file,application/zip, orapplication/x-pkcs12.
05Pagination
All list endpoints use cursor-based pagination:
GET /api/v1/projects/{projectId}/certificates?limit=50
# →
{
"items": [ ... ],
"next_cursor": "eyJpZCI6IC4uLn0="
}
GET /api/v1/projects/{projectId}/certificates?limit=50&cursor=eyJpZCI6IC4uLn0=
# → next page; returns empty next_cursor when exhausted
limit: default 50, max 500.cursor: opaque. Don't parse or manipulate.- Stable sort by ID — even if records are added or deleted mid-iteration, you don't skip or double-yield.
06Filtering & sorting
Per-endpoint query params. The pattern:
GET /api/v1/projects/{projectId}/certificates
?status=active,renewal_failed
&expiring_within_days=30
&issuer_type=acme
&sort=expires_at
&order=asc
Comma-separated lists for OR filters. Per-field knobs documented on each endpoint in the full reference.
07Error shape
HTTP 422 Unprocessable Entity
Content-Type: application/json
{
"error": {
"code": "policy_violation",
"message": "Key type ECDSA-P256 is not allowed by this project's policy.",
"details": [
{
"rule": "allowed_key_types",
"offending_value": "ECDSA-P256",
"allowed": ["RSA-2048", "RSA-3072"]
}
],
"request_id": "req_01H..."
}
}
code: machine-readable; stable per release.message: human-readable; may change wording.details: structured error context — present for validation / policy-violation / rate-limit errors.request_id: trace it in the audit log + OpenTelemetry trace.
08Common status codes
| Code | Meaning in this API |
|---|---|
| 200 | OK — GET / PATCH success. |
| 201 | Created — POST that created a resource. |
| 202 | Accepted — async action queued (e.g. cert issuance). |
| 204 | No Content — DELETE success. |
| 400 | Client error — malformed JSON, bad enum. |
| 401 | No auth / expired auth. |
| 403 | Authenticated but role insufficient. |
| 404 | Resource not found (or not visible to your tenant). |
| 409 | Conflict — duplicate, state precondition failed, license limit. |
| 422 | Unprocessable — policy violation, validation failure. |
| 429 | Rate-limited (auth failures or per-tenant quotas). |
| 503 | Service temporarily unavailable (scheduler rebooting, DB primary failover). |
09Idempotency
Every mutation accepts an Idempotency-Key header:
POST /api/v1/projects/{projectId}/certificates
Idempotency-Key: create-api-cert-2026-04-21
Content-Type: application/json
{ ... }
Repeating the same request within 24 h returns the original response — both on success and on error. Different bodies with the same key return 409. Skip the header if you don't need the safety; the server doesn't synthesise one.
10Rate limits
- API-key auth failures: 10 per IP per minute → 429.
- Per-tenant quotas: absent by default. Add at your reverse proxy / API gateway for multi-tenant deployments.
- CA-imposed limits: cert issuance respects the CA's weekly quotas (zone page surfaces them). Not the same as CertAutoPilot's own rate limit.
11Request correlation
- Every response carries
X-Request-ID. Log it; it's the key into the audit log and the OpenTelemetry trace. - Clients can set their own request ID by sending
X-Request-ID— the server echoes it.
12Client libraries
Official client: none (yet). Everything is plain JSON, so any curl / ky / requests / go http.Client works. OpenAPI spec lives at /api/v1/openapi.json — generate your own SDK with openapi-generator or similar.