---
title: PKI
path: reference/pki
status: published
---

# PKI Reference

Endpoint reference for PKI, CSRs, trust anchors, ACME. For guides, see [PKI Certificates](../api-guides/pki-certificates) and [ACME](../api-guides/acme). For the model, see [PKI](../core-concepts/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).

### GET /v1/pki/dns-providers/{id}

### PATCH /v1/pki/dns-providers/{id}

### DELETE /v1/pki/dns-providers/{id}

## Related

- [PKI Certificates](../api-guides/pki-certificates)
- [ACME](../api-guides/acme)
- [PKI (Concepts)](../core-concepts/pki)
