## Certificates (`certs`)

Uploaded or automatically issued HTTPS certificates. They can be bound to sites; a certificate in use by a site cannot be deleted or disabled.

Authentication: User (some parameters admin only) · Docs: https://www-demo.kuxitong.com/en/docs/api/certs

### GET `/api/v2/certs`

List certificates · Authentication: User (some parameters admin only)

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `page` | integer |  | Page number, starting from 1 Default: 1 |
| `page_size` | integer |  | Items per page Default: 20 |
| `sort` | string |  | Sort fields, comma-separated; prefix `-` for descending, e.g. `-created_at,id` |
| `tenant_id` | integer |  | Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data |
| `name` | string |  | Name contains. |
| `domain` | string |  | SAN contains (part of a domain or IP). |
| `scope` | string |  | site = site certificate; ip = platform IP certificate; panel = panel certificate (used by the controller's HTTPS listener). Values: ["site","ip","panel"] |
| `enabled` | boolean |  | Whether enabled |
| `expire_days` | integer |  | Only list certificates expiring within N days (including expired ones). |
| `id` | integer |  | Exact certificate ID match. |
| `ids` | string |  | Comma-separated certificate IDs (at most 200); matches any of them. Combined with id as an intersection. |
| `des` | string |  | Remark contains. |
| `type` | string |  | Certificate type. Values: ["custom","lets","zerossl","zerossl_api"] |
| `dns_api_id` | integer |  | Certificates using this DNS API credential. |
| `domains` | string |  | Comma-separated domains or IPs; matches certificates whose SAN contains any of them (exact match). |
| `issue_state` | string |  | ACME issuance state (uploaded certificates have none). Values: ["pending","running","issued","failed"] |
| `kind` | string |  | domain = SAN contains a domain; ip = SAN is all IPs. Values: ["domain","ip"] |

```sh
curl "https://panel.example.com/api/v2/certs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/certs`

Create certificate · Authentication: User (some parameters admin only)

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `tenant_id` | integer |  | Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data |

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `acme` | CertAcmeSummary |  | Issuance state summary (carried by certificate GET and list). Present only for issued certificates (type=lets/zerossl/zerossl_api); uploaded certificates (custom) do not have this field. See GET /certs/{id}/acme for the full state (challenge type, ARI window, etc.). |
| `cert` | string |  | Certificate chain PEM (leaf first, intermediates completed, root excluded); no private key (export it only via POST /certs/{id}/private-key). |
| `des` | string |  | Description |
| `enabled` | boolean |  | Whether enabled |
| `key` | string |  | Private key PEM (PKCS#1/PKCS#8/SEC1, must not be encrypted); omit when replacing the certificate to verify against the existing key. |
| `name` | string | Yes | Name |
| `scope` | string |  | Certificate scope: site = site certificate; ip = platform IP certificate; panel = panel certificate. Values: ["site","ip","panel"] |
| `type` | string |  | custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API. |

```sh
curl -X POST "https://panel.example.com/api/v2/certs" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/certs/acme-states`

Get ACME issuance states in batch · Authentication: User (some parameters admin only)

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `ids` | string | Yes | Certificate IDs, comma-separated, at most 200. |

```sh
curl "https://panel.example.com/api/v2/certs/acme-states" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/certs/batch`

Batch-create ACME certificates · Authentication: User (some parameters admin only)

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `tenant_id` | integer |  | Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data |

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `acme_account_id` | integer |  | Account to issue with (same as acme.acme_account_id in POST /certs); if omitted, the tenant's enabled account for the type is used first, then the platform's. |
| `auto_renew` | boolean |  | Defaults to true if omitted. |
| `des` | string |  | Description |
| `dns_api_id` | integer |  | DNS API credential used for DNS-01 validation (for ACME certificates). |
| `items` | CertAcme[] | Yes | Issuance states. |
| `type` | string |  | custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API. |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/batch" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"items":[{"domains":["a.example.com"]},{"domains":["b.example.com","www.b.example.com"]}],"type":"lets"}'
```

### POST `/api/v2/certs/batch-issue`

Batch reissue or renew ACME certificates · Authentication: User (some parameters admin only)

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `ids` | integer[] | Yes | Certificate IDs. |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/batch-issue" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"ids":[1]}'
```

### GET `/api/v2/certs/zerossl-ips`

List IPs eligible for ZeroSSL certificates · Authentication: User (some parameters admin only)

Query parameters:

| Field | Type | Required | Description |
|---|---|---|---|
| `tenant_id` | integer |  | Admin only: filter by tenant. Ignored for tenant credentials, which only see their own tenant's data |

```sh
curl "https://panel.example.com/api/v2/certs/zerossl-ips" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/certs/{id}`

Get certificate · Authentication: User (some parameters admin only)

```sh
curl "https://panel.example.com/api/v2/certs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/certs/{id}`

Update certificate · Authentication: User (some parameters admin only)

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `acme` | CertAcmeSummary |  | Issuance state summary (carried by certificate GET and list). Present only for issued certificates (type=lets/zerossl/zerossl_api); uploaded certificates (custom) do not have this field. See GET /certs/{id}/acme for the full state (challenge type, ARI window, etc.). |
| `cert` | string |  | Certificate chain PEM (leaf first, intermediates completed, root excluded); no private key (export it only via POST /certs/{id}/private-key). |
| `des` | string |  | Description |
| `enabled` | boolean |  | Whether enabled |
| `key` | string |  | Private key PEM (PKCS#1/PKCS#8/SEC1, must not be encrypted); omit when replacing the certificate to verify against the existing key. |
| `name` | string | Yes | Name |
| `scope` | string |  | Certificate scope: site = site certificate; ip = platform IP certificate; panel = panel certificate. Values: ["site","ip","panel"] |
| `type` | string |  | custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API. |

```sh
curl -X PUT "https://panel.example.com/api/v2/certs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### DELETE `/api/v2/certs/{id}`

Delete certificate · Authentication: User (some parameters admin only)

```sh
curl -X DELETE "https://panel.example.com/api/v2/certs/{id}" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### GET `/api/v2/certs/{id}/acme`

Get certificate ACME issuance status · Authentication: User (some parameters admin only)

```sh
curl "https://panel.example.com/api/v2/certs/{id}/acme" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### PUT `/api/v2/certs/{id}/acme`

Update certificate auto-renewal switch · Authentication: User (some parameters admin only)

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `auto_renew` | boolean | Yes | Defaults to true if omitted. |

```sh
curl -X PUT "https://panel.example.com/api/v2/certs/{id}/acme" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"auto_renew":false}'
```

### POST `/api/v2/certs/{id}/bind`

Bind certificate to sites · Authentication: User (some parameters admin only)

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `site_ids` | integer[] | Yes | Sites using this certificate. |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/{id}/bind" \
  -H "X-API-Key: $GOCDN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"site_ids":[1]}'
```

### POST `/api/v2/certs/{id}/issue`

Reissue ACME certificate · Authentication: User (some parameters admin only)

```sh
curl -X POST "https://panel.example.com/api/v2/certs/{id}/issue" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

### POST `/api/v2/certs/{id}/private-key`

Export certificate private key · Authentication: User (some parameters admin only)

Request body:

| Field | Type | Required | Description |
|---|---|---|---|
| `password` | string |  | Current login password. |
| `totp_code` | string |  | Current 6-digit TOTP code; the account must have TOTP enabled. |

```sh
curl -X POST "https://panel.example.com/api/v2/certs/{id}/private-key" \
  -H "X-API-Key: $GOCDN_API_KEY"
```

Certificates object:

| Field | Type | Required | Description |
|---|---|---|---|
| `acme` | CertAcmeSummary |  | Issuance state summary (carried by certificate GET and list). Present only for issued certificates (type=lets/zerossl/zerossl_api); uploaded certificates (custom) do not have this field. See GET /certs/{id}/acme for the full state (challenge type, ARI window, etc.). (read-only) |
| `acme_account_id` | integer |  | Account to issue with (same as acme.acme_account_id in POST /certs); if omitted, the tenant's enabled account for the type is used first, then the platform's. |
| `ari_end` | string |  | End of the renewal window suggested by the CA via ARI. |
| `ari_start` | string |  | Renewal window suggested by the CA via ARI; null = none given by the CA, renew cert.acme.renew_before_days days before expiry. |
| `auto_renew` | boolean |  | Defaults to true if omitted. |
| `cert` | string |  | Certificate chain PEM (leaf first, intermediates completed, root excluded); no private key (export it only via POST /certs/{id}/private-key). (read-only) |
| `cert_id` | integer |  | Certificate ID. |
| `challenge` | string |  | Validation method: http-01, dns-01, or http-file (ZeroSSL file validation for zerossl_api). Values: ["http-01","dns-01","http-file"] |
| `created_at` | string |  | Created at (read-only) |
| `des` | string |  | Description |
| `dns_api_id` | integer |  | DNS API credential used for DNS-01 validation (for ACME certificates). |
| `enabled` | boolean |  | Whether enabled |
| `err_times` | integer |  | Number of failures in the current round. |
| `failed` | integer |  | Number of failed items. |
| `fingerprint` | string |  | SHA-256 fingerprint of the leaf certificate (lowercase hex). (read-only) |
| `id` | integer |  | Record ID (read-only) |
| `ids` | integer[] | Yes | Certificate IDs. |
| `issued_at` | string |  | Time of the last successful issuance. |
| `issuer` | string |  | Certificate issuer. (read-only) |
| `items` | CertAcme[] |  | Issuance states. |
| `key` | string |  | Private key PEM (PKCS#1/PKCS#8/SEC1, must not be encrypted); omit when replacing the certificate to verify against the existing key. |
| `last_error` | string |  | Last error |
| `name` | string |  | Name |
| `names` | string[] |  | SANs (domains, wildcard domains or IPs); falls back to CN when there is no SAN. (read-only) |
| `next_try_at` | string |  | After a renewal ends in failure, the earliest time the renewal scan will retry. |
| `not_after` | string |  | Certificate expiry time. (read-only) |
| `not_before` | string |  | Time the certificate becomes valid. (read-only) |
| `ocsp` | boolean |  | The leaf certificate carries an OCSP URL (nodes can staple). (read-only) |
| `ok` | integer |  | Number of items queued for issuance. |
| `password` | string |  | Current login password. |
| `renewing` | boolean |  | The current round is a renewal (the old certificate stays in use on failure). |
| `scope` | string |  | Certificate scope: site = site certificate; ip = platform IP certificate; panel = panel certificate. Values: ["site","ip","panel"] |
| `site_ids` | integer[] |  | Sites using this certificate. (read-only) |
| `state` | string |  | pending = queued or waiting to retry; running = issuing; issued = issued; failed = retries exhausted (alert sent). Values: ["pending","running","issued","failed"] |
| `tenant_id` | integer |  | Owning tenant; null = platform IP certificate. (read-only) |
| `totp_code` | string |  | Current 6-digit TOTP code; the account must have TOTP enabled. |
| `type` | string |  | custom = uploaded; lets/zerossl = issued via ACME; zerossl_api = issued via the paid ZeroSSL REST API. |
| `updated_at` | string |  | Updated at (read-only) |
| `version` | integer |  | Certificate content version; incremented on each replacement. (read-only) |
| `zerossl_order_id` | string |  | Current ZeroSSL order ID of a zerossl_api certificate; empty = no order yet. |
| `zerossl_order_state` | string |  | ZeroSSL order status (draft, pending_validation, issued, cancelled, etc.); empty = no order yet. |
