TLS¶
Certificates for the service and each alias, issued via ACME or uploaded, plus the redirect from HTTP to HTTPS and HSTS. See API access.
Endpoints¶
| Method | Path | Key | Purpose |
|---|---|---|---|
GET |
/services/{fqdn}/aliases/{alias_fqdn}/ssl |
read | Certificate of an alias |
POST |
/services/{fqdn}/aliases/{alias_fqdn}/ssl |
write | Upload a certificate for an alias (ECDSA) |
POST |
/services/{fqdn}/aliases/{alias_fqdn}/ssl/issue |
write | Issue an alias certificate via ACME |
POST |
/services/{fqdn}/aliases/{alias_fqdn}/ssl/renew |
write | Renew an alias certificate |
GET |
/services/{fqdn}/ssl |
read | Certificate of a vService |
POST |
/services/{fqdn}/ssl |
write | Upload a certificate (ECDSA) |
POST |
/services/{fqdn}/ssl/issue |
write | Issue a certificate via ACME |
POST |
/services/{fqdn}/ssl/renew |
write | Renew the ACME certificate |
GET /services/{fqdn}/aliases/{alias_fqdn}/ssl
Returns: 200, CertificateStatus
Answer 200
{
"fqdn": "www.a.example.com",
"mode": "acme",
"has_custom_cert": false,
"cert_status": "none",
"cert_issued": null,
"cert_expires": null,
"cert_last_renewal": null,
"days_remaining": null,
"detail": null
}
POST /services/{fqdn}/aliases/{alias_fqdn}/ssl
Body: CertificateUpload
Returns: 200, CertificateStored
Request
{
"fullchain_pem": "-----BEGIN CERTIFICATE-----\nMIIBszCCAVmgAwIBAgIU...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBuDCCAV6gAwIBAgIU...\n-----END CERTIFICATE-----\n",
"privkey_pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEG...\n-----END PRIVATE KEY-----\n"
}
Answer 200
{
"fqdn": "www.a.example.com",
"mode": "custom",
"cert": {
"subject": "CN=a.example.com",
"issuer": "CN=Example CA",
"not_before": "2026-10-01T00:00:00+00:00",
"not_after": "2026-12-30T00:00:00+00:00",
"dns_names": [
"a.example.com",
"www.a.example.com"
],
"serial_number": "4f2a",
"chain_length": 2,
"key_type": "EC",
"key_bits": 256,
"curve": "secp256r1"
}
}
POST /services/{fqdn}/aliases/{alias_fqdn}/ssl/issue
Returns: 202, AcmeStarted
Answer 202
{
"status": "started",
"fqdn": "www.a.example.com"
}
POST /services/{fqdn}/aliases/{alias_fqdn}/ssl/renew
Returns: 202, AcmeStarted
Answer 202
{
"status": "started",
"fqdn": "www.a.example.com"
}
GET /services/{fqdn}/ssl
Returns: 200, CertificateStatus
Answer 200
{
"fqdn": "a.example.com",
"mode": "acme",
"has_custom_cert": false,
"cert_status": "none",
"cert_issued": null,
"cert_expires": null,
"cert_last_renewal": null,
"days_remaining": null,
"detail": null
}
POST /services/{fqdn}/ssl
Body: CertificateUpload
Returns: 200, CertificateStored
Request
{
"fullchain_pem": "-----BEGIN CERTIFICATE-----\nMIIBszCCAVmgAwIBAgIU...\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIBuDCCAV6gAwIBAgIU...\n-----END CERTIFICATE-----\n",
"privkey_pem": "-----BEGIN PRIVATE KEY-----\nMIGHAgEAMBMGByqGSM49AgEG...\n-----END PRIVATE KEY-----\n"
}
Answer 200
{
"fqdn": "a.example.com",
"mode": "custom",
"cert": {
"subject": "CN=a.example.com",
"issuer": "CN=Example CA",
"not_before": "2026-10-01T00:00:00+00:00",
"not_after": "2026-12-30T00:00:00+00:00",
"dns_names": [
"a.example.com",
"www.a.example.com"
],
"serial_number": "4f2a",
"chain_length": 2,
"key_type": "EC",
"key_bits": 256,
"curve": "secp256r1"
}
}
POST /services/{fqdn}/ssl/issue
Returns: 202, AcmeStarted
Answer 202
{
"status": "started",
"fqdn": "a.example.com"
}
POST /services/{fqdn}/ssl/renew
Returns: 202, AcmeStarted
Answer 202
{
"status": "started",
"fqdn": "a.example.com"
}
Fields¶
Part of the service: send them with PATCH /services/{fqdn}. ssl exists on the service
and on each alias; hsts sits in response_headers.
Ssl¶
| Field | Type | Notes |
|---|---|---|
mode |
string | one of acme, custom; default "acme"; acme: ZERO-PROTECT issues and renews the certificate, validating through the edge, so DNS must point here first. custom: you upload it and renew it yourself |
acme_provider |
string | one of letsencrypt, buypass, zerossl, google; default "zerossl"; Certificate authority for acme: letsencrypt, buypass, zerossl or google (Google Trust Services) |
acme_email |
string | may be null; Contact address for the certificate authority. Empty: the account's acme_email, then your tenant's contact address |
https_redirect |
boolean | default false; Redirect HTTP to HTTPS with 301 for this hostname: the vService's own name, or the alias under aliases[]. ACME validation stays on HTTP. Needs a certificate for that name |
cert_status |
string | one of issued, expiring, expired, error, pending, none; read-only; Derived from the certificate the edges serve; expiring = renewal not done yet, the certificate is still valid. Set by the server |
cert_issued |
string | may be null; read-only; Set by the server |
cert_expires |
string | may be null; read-only; Set by the server |
cert_last_renewal |
string | may be null; read-only; Set by the server |
days_remaining |
integer | may be null; read-only; Set by the server |
Hsts¶
| Field | Type | Notes |
|---|---|---|
enabled |
boolean | default false; Set Strict-Transport-Security on the responses the edge passes on, replacing your origin's |
max_age |
integer | 0–63072000; default 31536000; Seconds browsers remember to use HTTPS only, 0 to 63072000 |
include_subdomains |
boolean | default false; Add includeSubDomains: browsers use HTTPS for every subdomain as well |
preload |
boolean | default false; Add preload, the condition for the browsers' preload lists |
CertificateStatus¶
| Field | Type | Notes |
|---|---|---|
fqdn (required) |
string | The vService or alias |
mode (required) |
string | one of acme, custom; acme: issued and renewed by ZERO-PROTECT. custom: uploaded by you |
has_custom_cert |
boolean | A certificate is stored and served |
cert_status (required) |
string | one of issued, expiring, expired, error, pending, none; Derived from the certificate the edges serve; expiring = renewal not done yet, the certificate is still valid |
cert_issued |
string | may be null; When ZERO-PROTECT last obtained the certificate via ACME; null without ACME issuance |
cert_expires |
string | may be null; Expiry of the certificate last obtained via ACME; cert.not_after is read from the stored certificate itself |
cert_last_renewal |
string | may be null; When ZERO-PROTECT last renewed the certificate via ACME; null without ACME issuance |
cert |
CertificateDetails |
The stored certificate; absent when none is stored or it cannot be read |
days_remaining |
integer | may be null; Days until the certificate expires, rounded up; 0 or less once expired; null when unknown |
detail |
string | may be null; What the state means for you |
CertificateUpload¶
| Field | Type | Notes |
|---|---|---|
fullchain_pem (required) |
string | Leaf certificate first, then the intermediates, PEM |
privkey_pem (required) |
string | Unencrypted private key, PEM |
Example¶
Issue a certificate, check it, then redirect to HTTPS and send HSTS:
curl -s -X PATCH -H "Authorization: Bearer $ZP_KEY" -H 'Content-Type: application/json' \
$API/services/www.example.com -d '{"ssl": {"mode": "acme", "acme_provider": "letsencrypt"}}'
curl -s -X POST -H "Authorization: Bearer $ZP_KEY" $API/services/www.example.com/ssl/issue
curl -s -H "Authorization: Bearer $ZP_KEY" $API/services/www.example.com/ssl
curl -s -X PATCH -H "Authorization: Bearer $ZP_KEY" -H 'Content-Type: application/json' \
$API/services/www.example.com -d '{"ssl": {"https_redirect": true},
"response_headers": {"hsts": {"enabled": true, "max_age": 31536000}}}'
Behaviour¶
- ACME validates with HTTP-01 through the edge, so DNS must point at the service first. Issuance takes minutes after the DNS check passes.
- ACME certificates renew daily once less than 30 days remain.
- Own certificate (
mode: custom): upload certificate and key; you handle renewal. - Uploads accept ECDSA only: an edge core completes about 2850 handshakes per second with ECDSA P-256 against 535 with RSA-4096, capacity you need during a flood. If your CA issued RSA, request ECDSA P-256 or use ACME.
cert_statusanddays_remainingcome from the certificate the edges serve;detailsays what a state means for you. A failed issuance shows aserror; support sees the reason.- Each alias has its own certificate settings, under
/services/{fqdn}/aliases/{alias_fqdn}/ssl. https_redirectsends port 80 to 443 with a301, for the vService and all its aliases; an alias has no setting of its own.- TCP services can use the certificate for TLS at the edge, see Ports.