Automate renewals
There are two paths, and the difference is who holds the private key.
| Auto-renewal | API-driven | |
|---|---|---|
| Who creates the renewal | NextPKI’s scheduler | You |
| Who generates the key | NextPKI, ephemerally | You, on the serving host |
| CSR | Server-side | Yours |
| Best when | The certificate is deployed by NextPKI-adjacent tooling | The key must never leave the host |
Both still require a human with the approver role to approve. That is not
removable - see why.
Auto-renewal
Section titled “Auto-renewal”Flag the certificate for auto-renewal in the Console and pick a connector. A scheduler opens a renewal once the certificate enters a 30-day window before expiry.
Your integration then only has to watch for approved work and deploy the result. Nothing to build on the request side.
API-driven
Section titled “API-driven”Use this when the private key must be generated where the certificate will serve - which for most server certificates is the correct answer.
#!/usr/bin/env bashset -euo pipefail
CERT_ID="$1"CN="$2"
# 1. Key and CSR, on this host. The key never moves.openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 \ -nodes -keyout "/etc/ssl/private/${CN}.key.new" \ -out "/tmp/${CN}.csr" -subj "/CN=${CN}"chmod 600 "/etc/ssl/private/${CN}.key.new"
# 2. Open the renewal.renewal=$(curl -fsS -X POST \ "https://api.nextpki.com/v1/certificates/${CERT_ID}/renew" \ -H "Authorization: Bearer ${NEXTPKI_TOKEN}" \ -H "Content-Type: application/json" \ -d "$(jq -n --arg csr "$(cat "/tmp/${CN}.csr")" \ --arg connector "${NEXTPKI_CONNECTOR_ID}" \ '{connector_id: $connector, csr: $csr}')")
id=$(jq -r .id <<<"$renewal")echo "renewal ${id} opened, waiting for approval"
# 3. Wait for a terminal state. Break on all three, not just the happy one.while :; do state=$(curl -fsS "https://api.nextpki.com/v1/requests/${id}" \ -H "Authorization: Bearer ${NEXTPKI_TOKEN}" | jq -r .state) case "$state" in issued|deployed) echo "issued"; break ;; failed|cancelled) echo "renewal ended: ${state}" >&2; exit 1 ;; esac sleep 30doneYou cannot fetch the certificate through v1
Section titled “You cannot fetch the certificate through v1”The script above gets you to issued and stops there, because the v1 API does
not return certificate bytes. Every endpoint returns metadata - subject, issuer,
validity, fingerprint - and none returns the PEM.
So a fully closed renewal-to-deployment loop is not possible through the API today.
GET /v1/requests/{id} gives you new_cert_id, which is enough to know issuance
succeeded and to look the certificate up, but not to install it.
How to obtain the certificate today, and how to deploy it once you have it, is covered in deploy a renewed certificate. If this gap blocks you, say so - it is the most consequential hole in v1 and demand is what moves it.
Do not swap the key until the certificate is in service
Section titled “Do not swap the key until the certificate is in service”The pattern above writes ${CN}.key.new rather than overwriting. Promote the new
key only once you hold the matching certificate and a reload has succeeded.
Overwriting the key first means a failed renewal leaves you with a key that does not match the certificate you are still serving. That is a self-inflicted outage, and it is the most common way a renewal automation causes the incident it existed to prevent. See deploy a renewed certificate for the safe ordering.
Retries
Section titled “Retries”Renewal creation is not idempotent in v1 - there is no idempotency key. After an ambiguous timeout, list renewals for that certificate before retrying:
curl -fsS "https://api.nextpki.com/v1/requests?state=pending_approval&limit=200" \ -H "Authorization: Bearer ${NEXTPKI_TOKEN}" \| jq --arg cert "$CERT_ID" '[.items[] | select(.previous_cert_id == $cert)] | length'Non-zero means a renewal already exists. Retrying blindly gives an approver two identical requests and, if both are approved, two certificates on the bill.
Expect the guardrails
Section titled “Expect the guardrails”Bulk migrations trip the connector protections - circuit breaker at three failures in ten minutes, anomaly detection above five times the baseline rate, and spending caps checked before each order. Raise the caps before a migration rather than debugging failures during it. See CA connectors.