PKI
Endpoint reference for PKI, CSRs, trust anchors, ACME. For guides, see PKI Certificates and ACME. For the model, see PKI.
Base path: /v1/pki/
Certificate Authorities#
GET /v1/pki/ca#
List CAs. Scope: pki:admin.
POST /v1/pki/ca#
Create root or intermediate.
Body:
| Field | Required | Description |
|---|---|---|
name |
Yes | |
common_name |
Yes | Subject CN |
ca_type |
Yes | root or intermediate |
parent_ca_id |
For intermediates | |
key_type |
No | rsa/ec (default rsa) |
key_size |
No | 2048/4096 for RSA, 256/384 for EC |
validity_days |
No | Default 3650/1825 |
Scope: pki:admin.
GET /v1/pki/ca/{id}#
GET /v1/pki/ca/{id}/certificate#
Returns CA certificate in PEM.
POST /v1/pki/ca/{id}/revoke#
Revoke the CA (all certs under it are marked revoked).
Body: {"reason": "..."}.
Scope: pki:admin.
POST /v1/pki/ca/{id}/crl#
Force immediate CRL regeneration. Returns PEM and next update time.
GET /v1/pki/ca/{id}/crl#
Get current CRL (DER or PEM via Accept).
PKI Roles#
GET /v1/pki/roles#
POST /v1/pki/roles#
Create a role (constrains issuance).
Body:
| Field | Description |
|---|---|
name |
Tenant-unique |
ca_id |
Issuing CA |
allowed_domains |
Array of patterns |
allow_subdomains |
Boolean |
allow_ip_sans |
Boolean |
max_ttl |
Duration |
key_type, key_bits |
Required issued-key shape |
require_cn |
Reject CSRs without CN |
store_private_keys |
Default false |
GET /v1/pki/roles/{name}#
PATCH /v1/pki/roles/{name}#
DELETE /v1/pki/roles/{name}#
Certificates#
POST /v1/pki/issue/{role}#
Issue a cert against a role.
Body: common_name (required), alt_names, ip_sans, ttl.
Response: certificate, private_key, ca_chain, serial_number, not_after. Private key returned once.
Scope: pki:issue.
POST /v1/pki/sign/{role}#
Sign a CSR directly (no approval step).
Body: csr_pem, ttl, optional san override.
Scope: pki:issue.
GET /v1/pki/certificates#
List. Query: ca_id, expiring_within (duration), include_revoked, limit, cursor.
GET /v1/pki/certificates/{id}#
GET /v1/pki/certificates/{id}/pem#
Just the PEM.
PATCH /v1/pki/certificates/{id}#
Update tags or description.
POST /v1/pki/certificates/{id}/renew#
Issue a new cert with same subject.
POST /v1/pki/certificates/{id}/private-key#
Retrieve stored private key (requires role store_private_keys: true).
Scope: pki:issue.
POST /v1/pki/certificates/import#
Import external certificate.
Body: certificate_pem, private_key_pem?, chain_pem?, ca_id?.
POST /v1/pki/certificates/validate#
Validate chain.
Body: certificate_pem, chain_pem?, check_revocation?.
Response: valid, chain_valid, not_expired, not_revoked, trusted_anchor?, errors?, warnings?.
POST /v1/pki/revoke#
Revoke a certificate.
Body: serial_number, reason (RFC 5280), use_acme? (for ACME-issued certs).
Scope: pki:admin.
CSR Workflow#
GET /v1/pki/csr#
List. Query: status (pending|approved|rejected|signed).
POST /v1/pki/csr#
Generate a CSR in-vault (private key stays with ScaiVault).
Body: subject, san_dns?, san_ip?, san_email?, key_type, key_size.
POST /v1/pki/csr/import#
Import an external CSR.
Body: csr_pem.
GET /v1/pki/csr/{id}#
POST /v1/pki/csr/{id}/approve#
POST /v1/pki/csr/{id}/reject#
Body: {"reason": "..."}.
POST /v1/pki/csr/{id}/sign#
Sign approved CSR against a CA.
Body: ca_id, validity_days?, san?.
Response: IssuedCertificate.
DELETE /v1/pki/csr/{id}#
Trust Anchors#
GET /v1/pki/trust-anchors#
POST /v1/pki/trust-anchors#
Body: name, certificate_pem.
GET /v1/pki/trust-anchors/{id}#
DELETE /v1/pki/trust-anchors/{id}#
ACME#
GET /v1/pki/acme/accounts#
POST /v1/pki/acme/accounts#
Register ACME account.
Body:
| Field | Description |
|---|---|
name |
|
provider |
letsencrypt, zerossl, buypass, google, custom |
environment |
production, staging |
email |
Contact |
directory_url |
For provider: custom |
GET /v1/pki/acme/accounts/{id}#
DELETE /v1/pki/acme/accounts/{id}#
Deactivates the account.
POST /v1/pki/acme/issue#
Request a certificate.
Body:
| Field | Description |
|---|---|
account_id |
|
domains |
Array |
challenge_type |
http-01, dns-01, tls-alpn-01 |
auto_renew |
Default true |
Response: order_id, status, challenges.
GET /v1/pki/acme/orders#
List orders. Query: status, account_id.
GET /v1/pki/acme/orders/{id}#
POST /v1/pki/acme/orders/{id}/refresh#
Re-poll upstream status.
POST /v1/pki/acme/challenges/{id}/complete#
Manually trigger challenge solver (usually automatic).
DNS Providers#
GET /v1/pki/dns-providers#
POST /v1/pki/dns-providers#
Body: name, type (aws_route53, cloudflare, google_cloud_dns, azure_dns, digitalocean, hetzner, rfc2136, etc.), config (provider-specific, generally references secrets by path for credentials).