# API reference

All routes use your deployment's application host, shown here with the reserved example `https://pki.example.com`.

Administrative routes require an administrator session cookie and use the console's role checks. API keys and service accounts are not yet supported. Enrollment routes use protocol credentials; public revocation routes require none.

## Enrollment — SCEP (RFC 8894)

```text
GET  /scep/{endpoint-id}?operation=GetCACaps
GET  /scep/{endpoint-id}?operation=GetCACert
GET  /scep/{endpoint-id}?operation=PKIOperation&message=…
POST /scep/{endpoint-id}
```

Windows appends `/pkiclient.exe`; do not include it in the configured URL.

## Enrollment — ACME (RFC 8555)

```text
GET  /acme/{endpoint-id}/directory
GET  /acme/{endpoint-id}/new-nonce
POST /acme/{endpoint-id}/new-account
POST /acme/{endpoint-id}/new-order
POST /acme/{endpoint-id}/orders/{order-id}
POST /acme/{endpoint-id}/orders/{order-id}/finalize
POST /acme/{endpoint-id}/authorizations/{authz-id}
POST /acme/{endpoint-id}/challenges/{challenge-id}
POST /acme/{endpoint-id}/certificates/{order-id}
POST /acme/{endpoint-id}/key-change
POST /acme/{endpoint-id}/revoke-cert
```

Clients discover these routes from `/directory`. ARI is not implemented.

## Enrollment — EST (RFC 7030)

```text
GET  /.well-known/est/{endpoint-id}/cacerts        (no credentials)
GET  /.well-known/est/{endpoint-id}/csrattrs
POST /.well-known/est/{endpoint-id}/simpleenroll
POST /.well-known/est/{endpoint-id}/simplereenroll
```

HTTP Basic over TLS. `/serverkeygen` and `/fullcmc` return `404`.

## Revocation — public, unauthenticated

```text
GET      /pki/{organization-id}/{ca-id}/crl       application/pkix-crl
GET/POST /pki/{organization-id}/{ca-id}/ocsp      application/ocsp-response
GET      /pki/{organization-id}/{ca-id}/issuer    application/pkix-cert
```

Issued certificates include these URLs.

## Administration — SCEP

```text
POST /api/scep/endpoints
POST /api/scep/endpoints/{endpoint-id}/policy
POST /api/scep/endpoints/{endpoint-id}/enabled
POST /api/scep/endpoints/{endpoint-id}/delete
POST /api/scep/endpoints/{endpoint-id}/challenges
POST /api/scep/endpoints/{endpoint-id}/auth/static
POST /api/scep/endpoints/{endpoint-id}/auth/jamf
POST /api/scep/endpoints/{endpoint-id}/auth/{method}/enabled
GET  /api/scep/endpoints/{endpoint-id}/ca
POST /api/scep/intune/connect
POST /api/scep/intune/disconnect
```

Mint a one-time challenge with JSON:

```bash
curl -sS -X POST \
  https://pki.example.com/api/scep/endpoints/{endpoint-id}/challenges \
  -H 'Content-Type: application/json' \
  -d '{
        "expectedSubject": "CN=laptop-4193.corp.example.com",
        "expectedSANs": "laptop-4193.corp.example.com",
        "expectedEKUs": ["client_auth"],
        "externalId": "asset-4193",
        "ttlSeconds": 900
      }'

# → {"challenge":"…","expiresIn":"15m0s"}
```

All fields optional. `ttlSeconds` defaults to 900 and is capped at 24 hours. `expectedEKUs` may only narrow the endpoint's permitted list.

Endpoint deletion requires its name in `confirm_name`.

## Administration — ACME

```text
POST /api/acme/endpoints
POST /api/acme/endpoints/{endpoint-id}/policy
POST /api/acme/endpoints/{endpoint-id}/enabled
POST /api/acme/endpoints/{endpoint-id}/delete
POST /api/acme/endpoints/{endpoint-id}/credentials
POST /api/acme/endpoints/{endpoint-id}/credentials/{credential-id}/revoke
```

```bash
curl -sS -X POST \
  https://pki.example.com/api/acme/endpoints/{endpoint-id}/credentials \
  -H 'Content-Type: application/json' \
  -d '{"label":"ingress-prod","identifiers":["ingress.example.internal"],"single_use":false,"ttl_hours":24}'

# → {"directory":"…","kid":"…","hmac_key":"…","single_use":false}
```

The `hmac_key` is returned once.

## Administration — EST

```text
POST /api/est/endpoints
POST /api/est/endpoints/{endpoint-id}/policy
POST /api/est/endpoints/{endpoint-id}/enabled
POST /api/est/endpoints/{endpoint-id}/delete
POST /api/est/endpoints/{endpoint-id}/credentials
POST /api/est/endpoints/{endpoint-id}/credentials/{credential-id}/revoke
```

```bash
curl -sS -X POST \
  https://pki.example.com/api/est/endpoints/{endpoint-id}/credentials \
  -H 'Content-Type: application/json' \
  -d '{"username":"branch-gateways","label":"EMEA branches","identifiers":"gw-muc-01.example.internal","ttl_hours":720}'

# → {"url":"…","username":"branch-gateways","password":"…"}
```

The password is returned once.

## Certificate authorities and certificates

```text
POST /certificate-authorities
POST /certificate-authorities/{id}/status
POST /certificate-authorities/{id}/rotate
POST /certificate-authorities/{id}/delete
GET  /certificate-authorities/{id}/download
POST /certificate-authorities/import
POST /certificate-authorities/import/{id}/wrapped-key
POST /certificate-authorities/import/{id}/cancel
GET  /certificate-authorities/import/{id}/status

POST /certificates/issue          generate the keypair here
POST /certificates/csr            sign a CSR you supply
POST /certificates/{id}/revoke
GET  /certificates/{id}/download
```

## Integrations

```text
POST /integrations/jamf/scep-challenge/{endpoint-id}    HTTP Basic, per-device challenge
```

## Audit

```text
GET /audit
GET /audit.csv       same query, as a CSV attachment
```

Both accept the page's filter query parameters.

## Status codes

| Code                     | Where                   | Means                                                                                                                                     |
| ------------------------ | ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| `404`                    | Any enrollment endpoint | The endpoint does not exist or is disabled. These states are deliberately indistinguishable                                               |
| `403`                    | EST                     | The request arrived over plaintext. No `WWW-Authenticate` is sent, so a client cannot be tricked into resending its password in the clear |
| `401`                    | EST                     | Wrong username, wrong password, or a revoked credential. Identical in all three cases, by design                                          |
| `400` + problem document | ACME                    | An RFC 8555 error; the reason is also recorded on the order                                                                               |
| `429`                    | Any enrollment endpoint | Rate limited, per endpoint and source address                                                                                             |
