API Access
Automate certificate management with the REST API. The API supports two authentication methods: OAuth 2.1 and API keys, both with granular per-CA permissions.
Authenticating with OAuth
The API supports OAuth 2.1 with PKCE (S256). Once you have an access token, include it in the Authorization header:
Authorization: Bearer cm_oauth_xxxxxxxxxxxxCreating an OAuth Client
For server-side applications, create a confidential OAuth client in the dashboard under OAuth Clients. You'll receive a client_id and client_secret. Public clients (e.g. SPAs, CLI tools) can use Dynamic Client Registration instead — no secret is issued, but PKCE is required.
OAuth Endpoints
| Endpoint | URL |
|---|---|
| Authorization | https://certman.app/oauth/authorize |
| Token | https://certman.app/oauth/token |
| Revocation | https://certman.app/oauth/revoke |
| Dynamic Registration | https://certman.app/oauth/register |
Authorization Flow
- Redirect the user to the authorization endpoint with
response_type=code, yourclient_id, aredirect_uri, PKCEcode_challenge, andresource=https://api.certman.app - The user selects a workspace and grants per-CA permissions (read, issue, revoke)
- Exchange the returned authorization code for an access token at the token endpoint
- Confidential clients authenticate with
client_secret_post; public clients use PKCE only
Token Refresh
Access tokens expire after 1 hour. Use the refresh_token grant at the token endpoint to obtain a new access token without user interaction. Refresh tokens are valid for 30 days and rotate on each use — always store the new refresh token from the response.
Authenticating with an API Key
Navigate to API / MCP Access in the sidebar to create keys. API keys must be scoped to specific CAs — they don't have workspace-wide access. Each key can be granted specific permissions per CA:
- Read — View CA and certificate details
- Issue — Create new certificates
- Revoke — Revoke existing certificates
On the Free plan, API keys get full access (all three permissions) to selected CAs. The Pro plan allows granular control — for example, read-only access to one CA and read+issue for another.
Include your API key in the Authorization header:
Authorization: Bearer cm_xxxxxxxxxxxxBase URL
All API endpoints are available at https://api.certman.app
OpenAPI Specification
The full API specification is available in OpenAPI 3.0 format at https://api.certman.app/v1/openapi. You can use this with tools like Swagger Editor, Postman, or any OpenAPI-compatible client to explore and test the API.
Rate Limits
API requests are rate-limited to ensure fair usage. Certificate issuance and renewal operations have a lower limit due to their computational cost. If you exceed the rate limit, you'll receive a 429 response.
Error Format
All error responses follow a consistent format:
{ "error": "Human-readable error message" }Common HTTP status codes:
- 400 — Bad request (invalid parameters)
- 401 — Unauthorized (missing or invalid credentials)
- 403 — Forbidden (insufficient permissions)
- 404 — Not found
- 429 — Too many requests (rate limited)
- 500 — Internal server error
Endpoints
GET
/v1/whoami
Returns information about the authenticated API key, including the associated user, workspace, and permissions.
Example Request
curl https://api.certman.app/v1/whoami \
-H "Authorization: Bearer cm_xxxxxxxxxxxx"Response
{
"user": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "user@example.com"
},
"workspace": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "My Workspace",
"slug": "my-workspace"
},
"apiKey": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"name": "Production Key",
"prefix": "cm_prod"
},
"permissions": {
"880e8400-e29b-41d4-a716-446655440003": {
"canRead": true,
"canIssue": true,
"canRevoke": false
}
}
}
GET
/v1/cas
Returns a list of all Certificate Authorities that the API key has read access to. Revoked CAs are automatically excluded.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
parentCaId |
string | Filter by parent CA ID. Use to list only children of a specific CA. |
type |
string | root | intermediate | all (default: all) |
Example Request
curl https://api.certman.app/v1/cas \
-H "Authorization: Bearer cm_xxxxxxxxxxxx"Response
{
"cas": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production Root CA",
"common_name": "Production Root CA",
"organization": "Acme Corp",
"key_algorithm": "ECDSA-P384",
"valid_from": "2024-01-01T00:00:00.000Z",
"valid_to": "2034-01-01T00:00:00.000Z",
"created_at": "2024-01-01T00:00:00.000Z",
"parent_ca_id": null,
"depth": 0,
"path_length": null
},
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Production Intermediate CA",
"common_name": "Production Intermediate CA",
"organization": "Acme Corp",
"key_algorithm": "ECDSA-P256",
"valid_from": "2024-06-01T00:00:00.000Z",
"valid_to": "2029-06-01T00:00:00.000Z",
"created_at": "2024-06-01T00:00:00.000Z",
"parent_ca_id": "550e8400-e29b-41d4-a716-446655440000",
"depth": 1,
"path_length": 0
}
]
}
GET
/v1/cas/:id
Returns detailed information about a specific Certificate Authority, including its certificate PEM.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Certificate Authority ID |
Example Request
curl https://api.certman.app/v1/cas/550e8400-e29b-41d4-a716-446655440000 \
-H "Authorization: Bearer cm_xxxxxxxxxxxx"Response
{
"ca": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Production Root CA",
"common_name": "Production Root CA",
"organization": "Acme Corp",
"country": "US",
"state": "California",
"locality": "San Francisco",
"key_algorithm": "ECDSA-P384",
"certificate_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"serial_number": "01AB23CD45EF",
"valid_from": "2024-01-01T00:00:00.000Z",
"valid_to": "2034-01-01T00:00:00.000Z",
"created_at": "2024-01-01T00:00:00.000Z",
"has_passphrase": false,
"parent_ca_id": null,
"depth": 0,
"path_length": null,
"revoked_at": null,
"revocation_reason": null
}
}
GET
/v1/cas/:id/chain
Returns the full certificate chain for a CA, from the specified CA up to the root. Useful for building trust stores or verifying certificate chains.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Certificate Authority ID |
Example Request
curl https://api.certman.app/v1/cas/550e8400-e29b-41d4-a716-446655440000/chain \
-H "Authorization: Bearer cm_xxxxxxxxxxxx"Response
{
"caId": "660e8400-e29b-41d4-a716-446655440001",
"chainLength": 2,
"chain": [
"-----BEGIN CERTIFICATE-----\n(intermediate CA cert)\n-----END CERTIFICATE-----",
"-----BEGIN CERTIFICATE-----\n(root CA cert)\n-----END CERTIFICATE-----"
]
}
GET
/v1/certificates
Returns a paginated list of certificates with optional filtering. Only certificates from CAs that the API key has read access to are returned.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
caId |
string | Filter by Certificate Authority ID |
status |
string | active | revoked | all (default: all) |
search |
string | Search by common name (case-insensitive partial match) |
createdFrom |
string | Filter certificates created on or after this date (ISO 8601) |
createdTo |
string | Filter certificates created on or before this date (ISO 8601) |
expiringInDays |
integer | Filter certificates expiring within N days |
page |
integer | Page number (1-indexed) (default: 1) |
pageSize |
integer | Number of items per page (default: 20) |
Example Request
curl "https://api.certman.app/v1/certificates?status=active&pageSize=10" \
-H "Authorization: Bearer cm_xxxxxxxxxxxx"Response
{
"certificates": [
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"ca_id": "550e8400-e29b-41d4-a716-446655440000",
"common_name": "api.example.com",
"san_dns": [
"api.example.com",
"www.example.com"
],
"san_ip": [
"192.168.1.1"
],
"key_algorithm": "ECDSA-P256",
"valid_from": "2024-06-01T00:00:00.000Z",
"valid_to": "2025-06-01T00:00:00.000Z",
"serial_number": "AABBCCDD",
"revoked_at": null,
"revocation_reason": null,
"created_at": "2024-06-01T00:00:00.000Z"
}
],
"total": 42,
"page": 1,
"pageSize": 20,
"totalPages": 3
}
POST
/v1/certificates
Issues a new certificate from a Certificate Authority. Supports two modes: 'managed' (Certman generates the key pair) or 'csr' (you provide a Certificate Signing Request).
Idempotency: For CSR mode only, you can provide an Idempotency-Key header to ensure the request is idempotent. If you retry a request with the same key and body, you'll receive the same response. Keys expire after 24 hours. Managed mode does not support idempotency because each request generates a unique private key.
Request Body
| Parameter | Type | Description |
|---|---|---|
caId |
string | ID of the Certificate Authority to issue from |
mode |
string | managed | csr (default: managed) |
commonName |
string | Common name for the certificate (required for managed mode) |
sanDns |
string[] | DNS Subject Alternative Names (supports wildcards like *.example.com) |
sanIp |
string[] | IP address Subject Alternative Names (IPv4 or IPv6) |
keyAlgorithm |
string | RSA-2048 | RSA-4096 | ECDSA-P256 | ECDSA-P384 |
validityDays |
integer | Certificate validity in days (max 397 per CA/Browser Forum) |
csrPem |
string | Certificate Signing Request in PEM format (required for csr mode) |
caPassphrase |
string | CA passphrase (required if the CA is passphrase-protected) |
Example Request
curl -X POST https://api.certman.app/v1/certificates \
-H "Authorization: Bearer cm_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"caId": "550e8400-e29b-41d4-a716-446655440000",
"mode": "managed",
"commonName": "api.example.com",
"sanDns": [
"api.example.com",
"www.example.com"
],
"sanIp": [
"192.168.1.1"
],
"keyAlgorithm": "ECDSA-P256",
"validityDays": 365
}'Response
{
"certificate": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"common_name": "api.example.com",
"certificate_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"san_dns": [
"api.example.com",
"www.example.com"
],
"san_ip": [
"192.168.1.1"
],
"valid_from": "2024-06-01T00:00:00.000Z",
"valid_to": "2025-06-01T00:00:00.000Z",
"serial_number": "AABBCCDD",
"created_at": "2024-06-01T00:00:00.000Z"
},
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}Note: privateKey is only returned for managed certificates. Store it securely.
POST
/v1/certificates/:id/revoke
Revokes a certificate. Revoked certificates are included in the CA's Certificate Revocation List (CRL) and will be reported as revoked via OCSP.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Certificate ID |
Request Body (Optional)
| Parameter | Type | Description |
|---|---|---|
reason |
string | unspecified | keyCompromise | caCompromise | affiliationChanged | superseded | cessationOfOperation | certificateHold | privilegeWithdrawn (default: unspecified) |
caPassphrase |
string | CA passphrase (required if the CA is passphrase-protected) |
Example Request
curl -X POST https://api.certman.app/v1/certificates/550e8400-e29b-41d4-a716-446655440000/revoke \
-H "Authorization: Bearer cm_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"reason": "keyCompromise"
}'Response
{
"message": "Certificate revoked successfully",
"certificate": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"common_name": "api.example.com",
"revoked_at": "2024-07-15T12:30:00.000Z",
"revocation_reason": "keyCompromise"
}
}
POST
/v1/certificates/:id/renew
Creates a new certificate with the same properties as an existing certificate. For managed certificates, a new key pair is generated. For CSR-based certificates, you must provide a new CSR.
Idempotency: When providing a CSR, you can use an Idempotency-Key header to ensure the request is idempotent. If you retry a request with the same key and body, you'll receive the same response. Keys expire after 24 hours. Managed renewals do not support idempotency because each request generates a unique private key.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
UUID | Certificate ID |
Request Body (Optional)
| Parameter | Type | Description |
|---|---|---|
validityDays |
integer | Certificate validity in days (max 397 per CA/Browser Forum) |
csrPem |
string | New CSR in PEM format (required when renewing a CSR-based certificate) |
caPassphrase |
string | CA passphrase (required if the CA is passphrase-protected) |
Example Request
curl -X POST https://api.certman.app/v1/certificates/550e8400-e29b-41d4-a716-446655440000/renew \
-H "Authorization: Bearer cm_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"validityDays": 365
}'Response
{
"message": "Certificate renewed successfully",
"certificate": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"common_name": "api.example.com",
"certificate_pem": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
"san_dns": [
"api.example.com",
"www.example.com"
],
"san_ip": [
"192.168.1.1"
],
"valid_from": "2025-06-01T00:00:00.000Z",
"valid_to": "2026-06-01T00:00:00.000Z",
"serial_number": "EEFF0011",
"created_at": "2025-06-01T00:00:00.000Z"
},
"privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}Note: privateKey is only returned for managed certificates. Store it securely.