Version: 2.48+
Base URL:https://your-server:8443/api/v2
Last Updated: February 2026
Total Endpoints: 347
Test Coverage: 1364 tests (~95% route coverage)
Note: All endpoints are served fromapi/v2/(34 registered blueprints). There is no separatefeatures/module.
- Authentication
- Account Management
- Certificate Authorities (CAs)
- Certificates
- User Certificates (mTLS)
- Certificate Signing Requests (CSRs)
- Templates
- Trust Store
- ACME Server
- SCEP
- CRL & OCSP
- Users
- Roles & Permissions (RBAC)
- Dashboard
- Audit Logs
- Settings
- System
- Import/Export
- Certificate Tools
- Global Search
- User Groups
- Smart Import
- DNS Providers
- ACME Client (Let's Encrypt)
- ACME Domains
- SSO (LDAP/OAuth2/SAML)
- HSM
- WebAuthn
- Webhooks
- Certificate Policies & Approvals
- Reports
- WebSocket
- Health
All API responses follow this structure:
// Success
{
"data": { ... },
"message": "Optional success message",
"meta": { "page": 1, "per_page": 50, "total": 100 } // For paginated responses
}
// Error
{
"error": true,
"code": 400,
"message": "Error description"
}UCM supports multiple authentication methods: Password, WebAuthn (Hardware Keys), and mTLS (Client Certificates).
POST /api/v2/auth/login/password
Content-Type: application/json
{
"username": "admin",
"password": "your-password"
}Response:
{
"data": {
"user": {
"id": 1,
"username": "admin",
"email": "[email protected]",
"role": "admin"
},
"role": "admin",
"permissions": ["*"],
"auth_method": "password"
},
"message": "Login successful"
}# Step 1: Get authentication options
POST /api/v2/auth/login/webauthn/start
Content-Type: application/json
{
"username": "admin"
}
# Step 2: Verify authentication
POST /api/v2/auth/login/webauthn/verify
Content-Type: application/json
{
"username": "admin",
"response": { ... } // WebAuthn credential response
}POST /api/v2/auth/login/mtls
# Requires client certificate in TLS handshakePOST /api/v2/auth/methods
Content-Type: application/json
{
"username": "admin"
}Response:
{
"data": {
"password": true,
"webauthn": true,
"webauthn_credentials": 2,
"mtls": false,
"mtls_status": "not_present",
"totp_enabled": true
}
}GET /api/v2/auth/verifyPOST /api/v2/auth/logoutPOST /api/v2/auth/forgot-password
Content-Type: application/json
{
"email": "[email protected]"
}POST /api/v2/auth/reset-password
Content-Type: application/json
{
"token": "reset-token-from-email",
"password": "NewSecurePassword123!"
}GET /api/v2/auth/email-configuredResponse:
{
"data": {
"configured": true
}
}# Get profile
GET /api/v2/account/profile
# Update profile
PATCH /api/v2/account/profile
Content-Type: application/json
{
"full_name": "John Doe",
"email": "[email protected]"
}
# Change password
POST /api/v2/account/password
Content-Type: application/json
{
"current_password": "old-password",
"new_password": "new-password"
}# Enable 2FA - returns QR code
POST /api/v2/account/2fa/enable
# Confirm 2FA with TOTP code
POST /api/v2/account/2fa/confirm
Content-Type: application/json
{
"code": "123456"
}
# Disable 2FA
POST /api/v2/account/2fa/disable
Content-Type: application/json
{
"code": "123456"
}
# Get recovery codes
GET /api/v2/account/2fa/recovery-codes
# Regenerate recovery codes
POST /api/v2/account/2fa/recovery-codes/regenerate# List API keys
GET /api/v2/account/apikeys
# Create API key
POST /api/v2/account/apikeys
Content-Type: application/json
{
"name": "CI/CD Integration",
"expires_days": 365,
"permissions": ["read:certificates", "write:certificates"]
}
# Get API key details
GET /api/v2/account/apikeys/{key_id}
# Update API key
PATCH /api/v2/account/apikeys/{key_id}
Content-Type: application/json
{
"name": "Updated Name",
"enabled": true
}
# Regenerate API key
POST /api/v2/account/apikeys/{key_id}/regenerate
# Delete API key
DELETE /api/v2/account/apikeys/{key_id}# Check WebAuthn availability
GET /api/v2/account/webauthn/available
# List credentials
GET /api/v2/account/webauthn/credentials
# Register new credential - Step 1
POST /api/v2/account/webauthn/register/options
# Register new credential - Step 2
POST /api/v2/account/webauthn/register/verify
Content-Type: application/json
{
"name": "YubiKey 5",
"response": { ... } // WebAuthn attestation response
}
# Toggle credential
POST /api/v2/account/webauthn/credentials/{credential_id}/toggle
# Delete credential
DELETE /api/v2/account/webauthn/credentials/{credential_id}# List enrolled certificates
GET /api/v2/account/mtls/certificates
# List all certificates (admin)
GET /api/v2/account/mtls/certificates/all
# Create new mTLS certificate
POST /api/v2/account/mtls/certificates/create
Content-Type: application/json
{
"name": "My Laptop",
"validity_days": 365
}
# Enroll existing certificate
POST /api/v2/account/mtls/certificates/enroll
# Download certificate
GET /api/v2/account/mtls/certificates/{cert_id}/download?format=pem
# Enable/disable certificate
POST /api/v2/account/mtls/certificates/{cert_id}/enable
Content-Type: application/json
{
"enabled": true
}
# Revoke certificate
POST /api/v2/account/mtls/certificates/{cert_id}/revoke
# Delete certificate
DELETE /api/v2/account/mtls/certificates/{cert_id}
# Get mTLS settings
GET /api/v2/account/mtls/settings
# Update mTLS settings
PUT /api/v2/account/mtls/settings
Content-Type: application/json
{
"enabled": true,
"issuing_ca_id": 1
}# List active sessions
GET /api/v2/account/sessions
# Revoke specific session
DELETE /api/v2/account/sessions/{session_id}
# Revoke all sessions except current
POST /api/v2/account/sessions/revoke-allGET /api/v2/account/activity?limit=50GET /api/v2/cas
GET /api/v2/cas?page=1&per_page=20Response:
{
"data": [
{
"id": 1,
"name": "Root CA",
"common_name": "UCM Root CA",
"ca_type": "root",
"serial_number": "0x1",
"valid_from": "2025-01-01T00:00:00",
"valid_until": "2035-01-01T00:00:00",
"key_size": 4096,
"signature_algorithm": "sha256WithRSAEncryption",
"is_active": true,
"certificates_count": 42
}
],
"meta": { "page": 1, "per_page": 20, "total": 3 }
}GET /api/v2/cas/treeResponse:
{
"data": [
{
"id": 1,
"name": "Root CA",
"ca_type": "root",
"children": [
{
"id": 2,
"name": "Intermediate CA",
"ca_type": "intermediate",
"parent_id": 1,
"children": []
}
]
}
]
}POST /api/v2/cas
Content-Type: application/json
{
"common_name": "My Root CA",
"organization": "My Company",
"country": "US",
"state": "California",
"locality": "San Francisco",
"key_size": 4096,
"validity_days": 3650,
"ca_type": "root",
"key_algorithm": "RSA"
}For Intermediate CA:
{
"common_name": "My Intermediate CA",
"parent_id": 1,
"ca_type": "intermediate",
"validity_days": 1825,
"key_size": 4096
}GET /api/v2/cas/{ca_id}PATCH /api/v2/cas/{ca_id}
Content-Type: application/json
{
"name": "Updated Name",
"is_active": true
}DELETE /api/v2/cas/{ca_id}GET /api/v2/cas/{ca_id}/certificates
GET /api/v2/cas/{ca_id}/certificates?status=active&page=1&per_page=50GET /api/v2/cas/{ca_id}/export?format=pem
GET /api/v2/cas/{ca_id}/export?format=der
GET /api/v2/cas/{ca_id}/export?format=chainGET /api/v2/cas/exportPOST /api/v2/cas/bulk/delete
Content-Type: application/json
{
"ids": [1, 2, 3]
}Response:
{
"data": {
"success": [1, 2],
"failed": [3]
}
}POST /api/v2/cas/bulk/export
Content-Type: application/json
{
"ids": [1, 2, 3]
}Returns a ZIP file containing the exported CA certificates.
GET /api/v2/certificates
GET /api/v2/certificates?status=active&ca_id=1&page=1&per_page=50
GET /api/v2/certificates?status=expiring&per_page=10
GET /api/v2/certificates?search=example.comQuery Parameters:
| Parameter | Type | Description |
|---|---|---|
status |
string | Filter: active, expired, revoked, expiring |
ca_id |
integer | Filter by issuing CA |
search |
string | Search in CN, SANs |
page |
integer | Page number (default: 1) |
per_page |
integer | Items per page (default: 50, max: 100) |
POST /api/v2/certificates
Content-Type: application/json
{
"common_name": "server.example.com",
"ca_id": 2,
"template_id": 1,
"validity_days": 365,
"key_size": 2048,
"san": ["dns:server.example.com", "dns:www.example.com", "ip:192.168.1.10"],
"key_usage": ["digitalSignature", "keyEncipherment"],
"extended_key_usage": ["serverAuth", "clientAuth"]
}Response:
{
"data": {
"id": 42,
"serial_number": "0x2A",
"common_name": "server.example.com",
"status": "active",
"valid_from": "2026-01-28T00:00:00",
"valid_until": "2027-01-28T00:00:00",
"private_key_available": true
},
"message": "Certificate issued successfully"
}GET /api/v2/certificates/{cert_id}# PEM format (certificate only)
GET /api/v2/certificates/{cert_id}/export?format=pem
# PEM with private key
GET /api/v2/certificates/{cert_id}/export?format=pem&include_key=true
# PKCS12 (PFX)
GET /api/v2/certificates/{cert_id}/export?format=pkcs12&password=export-password
# DER format
GET /api/v2/certificates/{cert_id}/export?format=der
# Full chain
GET /api/v2/certificates/{cert_id}/export?format=chainPOST /api/v2/certificates/{cert_id}/renew
Content-Type: application/json
{
"validity_days": 365
}POST /api/v2/certificates/{cert_id}/revoke
Content-Type: application/json
{
"reason": "keyCompromise",
"comments": "Private key was exposed"
}Revocation Reasons:
unspecifiedkeyCompromisecaCompromiseaffiliationChangedsupersededcessationOfOperation
POST /api/v2/certificates/import
Content-Type: application/json
{
"certificate": "-----BEGIN CERTIFICATE-----\n...",
"private_key": "-----BEGIN PRIVATE KEY-----\n...",
"ca_id": 1
}DELETE /api/v2/certificates/{cert_id}GET /api/v2/certificates/statsPOST /api/v2/certificates/{cert_id}/key
Content-Type: application/json
{
"passphrase": "optional-passphrase"
}GET /api/v2/certificates/exportPOST /api/v2/certificates/bulk/revoke
Content-Type: application/json
{
"ids": [1, 2, 3],
"reason": "keyCompromise"
}Response:
{
"data": {
"success": [1, 2],
"failed": [3]
}
}POST /api/v2/certificates/bulk/renew
Content-Type: application/json
{
"ids": [1, 2, 3],
"ca_id": 2
}POST /api/v2/certificates/bulk/delete
Content-Type: application/json
{
"ids": [1, 2, 3]
}POST /api/v2/certificates/bulk/export
Content-Type: application/json
{
"ids": [1, 2, 3]
}Returns a ZIP file containing the exported certificates.
Manage mTLS client certificates enrolled via the Account page. These certificates are stored in the main certificates table (with cert_type='usr_cert') and linked to users via auth_certificates.
Permissions: read:user_certificates, write:user_certificates, delete:user_certificates
Ownership: Viewers see only their own certificates. Operators and admins see all.
GET /api/v2/user-certificates
GET /api/v2/user-certificates?status=valid&page=1&per_page=50Query Parameters:
| Param | Type | Description |
|---|---|---|
| status | string | Filter by status: valid, expired, revoked |
| page | int | Page number (default: 1) |
| per_page | int | Items per page (default: 50) |
Response 200:
{
"data": {
"items": [
{
"id": 1,
"cert_id": 52,
"common_name": "admin@mtls",
"cn": "admin@mtls",
"status": "valid",
"days_remaining": 364,
"has_private_key": true,
"created_at": "2026-02-20T19:05:19",
"not_valid_after": "2027-02-20T19:05:19",
"issuer": "CN=lan.pew.pet,O=Pew Pet",
"username": "admin"
}
],
"total": 1,
"page": 1,
"per_page": 50
}
}GET /api/v2/user-certificates/statsResponse 200:
{
"data": {
"total": 5,
"valid": 3,
"expired": 1,
"revoked": 1,
"expiring_soon": 0
}
}GET /api/v2/user-certificates/{id}Response 200: Full certificate details including common_name, cn, days_remaining, key_algorithm, signature_algorithm, serial_number, fingerprint.
GET /api/v2/user-certificates/{id}/export?format=pem&include_key=true&include_chain=true
GET /api/v2/user-certificates/{id}/export?format=pkcs12&password=mypasswordQuery Parameters:
| Param | Type | Description |
|---|---|---|
| format | string | pem (default) or pkcs12 |
| include_key | bool | Include private key (default: true) |
| include_chain | bool | Include CA chain (default: true) |
| password | string | PKCS12 password (required for pkcs12, min 8 chars) |
Response 200: Binary file download with Content-Disposition header.
Note: Auditors are explicitly blocked from exporting user certificates.
POST /api/v2/user-certificates/{id}/revokeBody:
{
"reason": "unspecified"
}Reason values: unspecified, key_compromise, ca_compromise, affiliation_changed, superseded, cessation_of_operation
Response 200:
{
"message": "Certificate revoked successfully",
"data": { ... }
}DELETE /api/v2/user-certificates/{id}Response 204: No content.
Note: Only admins and operators can delete. Deletes both the
auth_certificateslink and the underlying certificate.
GET /api/v2/csrs
GET /api/v2/csrs?status=pending&page=1&per_page=50POST /api/v2/csrs
Content-Type: application/json
{
"csr": "-----BEGIN CERTIFICATE REQUEST-----\n...",
"name": "My Server CSR"
}GET /api/v2/csrs/{csr_id}POST /api/v2/csrs/{csr_id}/sign
Content-Type: application/json
{
"ca_id": 2,
"validity_days": 365,
"template_id": 1
}DELETE /api/v2/csrs/{csr_id}POST /api/v2/csrs/upload
Content-Type: application/json
{
"pem": "-----BEGIN CERTIFICATE REQUEST-----\n...",
"name": "My Server CSR"
}POST /api/v2/csrs/import
Content-Type: multipart/form-data
file: <CSR file>
name: "My Server CSR"Alternatively, via JSON body:
POST /api/v2/csrs/import
Content-Type: application/json
{
"pem_content": "-----BEGIN CERTIFICATE REQUEST-----\n...",
"name": "My Server CSR"
}GET /api/v2/csrs/history
GET /api/v2/csrs/history?page=1&per_page=50GET /api/v2/csrs/{csr_id}/exportReturns the CSR as a PEM file download.
POST /api/v2/csrs/{csr_id}/key
Content-Type: application/json
{
"key": "-----BEGIN PRIVATE KEY-----\n...",
"passphrase": "optional-passphrase"
}POST /api/v2/csrs/bulk/sign
Content-Type: application/json
{
"ids": [1, 2, 3],
"ca_id": 2,
"validity_days": 365
}Response:
{
"data": {
"success": [1, 2],
"failed": [3]
}
}POST /api/v2/csrs/bulk/delete
Content-Type: application/json
{
"ids": [1, 2, 3]
}GET /api/v2/templatesPOST /api/v2/templates
Content-Type: application/json
{
"name": "Web Server",
"description": "Template for web server certificates",
"validity_days": 365,
"key_size": 2048,
"key_usage": ["digitalSignature", "keyEncipherment"],
"extended_key_usage": ["serverAuth"],
"basic_constraints": {
"ca": false
}
}GET /api/v2/templates/{template_id}PUT /api/v2/templates/{template_id}
Content-Type: application/json
{
"name": "Updated Web Server",
"validity_days": 730
}DELETE /api/v2/templates/{template_id}POST /api/v2/templates/bulk/delete
Content-Type: application/json
{
"ids": [1, 2, 3]
}GET /api/v2/templates/{template_id}/exportReturns the template as a JSON file.
GET /api/v2/templates/exportReturns all templates as a JSON array.
POST /api/v2/templates/import
Content-Type: multipart/form-data
file: <template JSON file>
update_existing: trueAlternatively, via JSON body:
POST /api/v2/templates/import
Content-Type: application/json
{
"json_content": "[{...}]",
"update_existing": true
}Response:
{
"data": {
"imported": 2,
"updated": 1,
"skipped": 0
}
}GET /api/v2/truststorePOST /api/v2/truststore
Content-Type: application/json
{
"certificate": "-----BEGIN CERTIFICATE-----\n...",
"name": "External Root CA",
"description": "Third-party CA for partner integration"
}GET /api/v2/truststore/{cert_id}DELETE /api/v2/truststore/{cert_id}POST /api/v2/truststore/syncGET /api/v2/truststore/statsResponse:
{
"data": {
"total": 25,
"root_ca": 10,
"intermediate_ca": 12,
"expired": 3,
"valid": 22
}
}POST /api/v2/truststore/import
Content-Type: multipart/form-data
file: <certificate file>
name: "External Root CA"
purpose: "trust_anchor"
description: "Third-party CA"
notes: "Optional notes"GET /api/v2/acme/settingsPATCH /api/v2/acme/settings
Content-Type: application/json
{
"enabled": true,
"issuing_ca_id": 2,
"validity_days": 90,
"require_approval": false
}GET /api/v2/acme/statsGET /api/v2/acme/accountsGET /api/v2/acme/ordersPOST /api/v2/acme/proxy/register
Content-Type: application/json
{
"email": "[email protected]",
"agree_tos": true
}GET /api/v2/scep/configResponse:
{
"data": {
"enabled": true,
"url": "/scep/pkiclient.exe",
"ca_id": 2,
"ca_ident": "ucm-ca",
"auto_approve": false,
"challenge_validity": 24
}
}PATCH /api/v2/scep/config
Content-Type: application/json
{
"enabled": true,
"ca_id": 2,
"ca_ident": "ucm-ca",
"auto_approve": false,
"challenge_validity": 24
}GET /api/v2/scep/statsGET /api/v2/scep/requests
GET /api/v2/scep/requests?status=pendingPOST /api/v2/scep/{request_id}/approvePOST /api/v2/scep/{request_id}/reject
Content-Type: application/json
{
"reason": "Invalid device"
}GET /api/v2/scep/challenge/{ca_id}POST /api/v2/scep/challenge/{ca_id}/regenerateGET /api/v2/crlGET /api/v2/crl/{ca_id}POST /api/v2/crl/{ca_id}/regenerateGET /api/v2/ocsp/statusGET /api/v2/ocsp/statsPublic endpoints for downloading CA certificates (RFC 5280 §4.2.2.1). No authentication required.
GET /ca/{ca_refid}.cerResponse: application/pkix-cert — DER-encoded X.509 certificate
Also accepts legacy numeric CA ID: GET /ca/{ca_id}.cer
curl http://your-server:8080/ca/550e8400-e29b-41d4-a716-446655440000.cer -o ca.cer
openssl x509 -in ca.cer -inform DER -text -nooutGET /ca/{ca_refid}.pemResponse: application/x-pem-file — PEM-encoded X.509 certificate
curl http://your-server:8080/ca/550e8400-e29b-41d4-a716-446655440000.pem -o ca.pemPer-CA toggle available via the CRL/OCSP management page or API:
GET /api/v2/cas/{ca_id} # Returns aia_ca_issuers_enabled, aia_ca_issuers_url
PUT /api/v2/cas/{ca_id} # Set aia_ca_issuers_enabled: true/falseWhen enabled, issued certificates include the CA Issuers URL in their Authority Information Access extension:
Authority Information Access:
OCSP - URI:http://your-server:8080/ocsp
CA Issuers - URI:http://your-server:8080/ca/{ca_refid}.cer
GET /api/v2/usersPOST /api/v2/users
Content-Type: application/json
{
"username": "newuser",
"email": "[email protected]",
"password": "SecurePassword123!",
"role": "operator",
"full_name": "New User"
}GET /api/v2/users/{user_id}PUT /api/v2/users/{user_id}
Content-Type: application/json
{
"email": "[email protected]",
"role": "admin",
"full_name": "Updated Name"
}PATCH /api/v2/users/{user_id}/togglePOST /api/v2/users/{user_id}/reset-password
Content-Type: application/json
{
"new_password": "NewSecurePassword123!"
}POST /api/v2/users/import
Content-Type: application/json
{
"users": [
{
"username": "user1",
"email": "[email protected]",
"role": "viewer"
}
],
"send_invites": true
}DELETE /api/v2/users/{user_id}GET /api/v2/rbac/rolesResponse:
{
"data": {
"roles": ["admin", "operator", "auditor", "viewer"],
"role_permissions": {
"admin": ["*"],
"operator": ["read:*", "write:certificates", "write:cas", ...],
"viewer": ["read:*"]
}
}
}GET /api/v2/rbac/roles/{role}GET /api/v2/rbac/permissionsGET /api/v2/dashboard/statsResponse:
{
"data": {
"total_certificates": 150,
"active_certificates": 120,
"expired_certificates": 25,
"revoked_certificates": 5,
"expiring_soon": 8,
"total_cas": 3,
"total_csrs": 12,
"pending_csrs": 3
}
}GET /api/v2/dashboard/expiring-certs?days=30&limit=10GET /api/v2/dashboard/recent-cas?limit=5GET /api/v2/dashboard/activity?limit=20&offset=0GET /api/v2/dashboard/system-statusResponse:
{
"data": {
"status": "healthy",
"database": "connected",
"disk_usage": {
"used": "2.1GB",
"total": "50GB",
"percent": 4.2
},
"uptime": "15 days, 3:42:15",
"version": "2.x"
}
}GET /api/v2/dashboard/certificate-trend?days=30Response:
{
"data": {
"trend": [
{ "date": "2026-01-28", "issued": 5, "revoked": 1 },
{ "date": "2026-01-29", "issued": 3, "revoked": 0 }
]
}
}GET /api/v2/stats/overviewResponse:
{
"data": {
"total_cas": 3,
"total_certs": 150,
"acme_accounts": 2,
"active_users": 5
}
}GET /api/v2/audit/logs
GET /api/v2/audit/logs?page=1&per_page=50
GET /api/v2/audit/logs?username=admin&action=login_success
GET /api/v2/audit/logs?success=false&date_from=2026-01-01Query Parameters:
| Parameter | Type | Description |
|---|---|---|
page |
integer | Page number |
per_page |
integer | Items per page (max: 100) |
username |
string | Filter by username |
action |
string | Filter by action type |
success |
boolean | Filter by success/failure |
date_from |
string | Start date (ISO format) |
date_to |
string | End date (ISO format) |
search |
string | Search in details |
Response:
{
"data": [
{
"id": 1,
"timestamp": "2026-01-28T18:00:00",
"username": "admin",
"action": "login_success",
"resource_type": "user",
"resource_id": "1",
"details": "Password login successful",
"ip_address": "192.168.1.100",
"user_agent": "Mozilla/5.0...",
"success": true
}
],
"meta": { "page": 1, "per_page": 50, "total": 100 }
}GET /api/v2/audit/logs/{log_id}GET /api/v2/audit/stats?days=30Response:
{
"data": {
"total_logs": 1250,
"success_count": 1200,
"failure_count": 50,
"success_rate": 96.0,
"top_actions": [
{ "action": "login_success", "count": 500 },
{ "action": "certificate_issued", "count": 200 }
],
"top_users": [
{ "username": "admin", "count": 800 }
],
"recent_failures": [...]
}
}GET /api/v2/audit/actionsGET /api/v2/audit/export?format=json&limit=10000
GET /api/v2/audit/export?format=csv&date_from=2026-01-01POST /api/v2/audit/cleanup
Content-Type: application/json
{
"retention_days": 90
}GET /api/v2/audit/verify
GET /api/v2/audit/verify?start_id=1&end_id=1000Response:
{
"data": {
"valid": true,
"checked": 1000,
"errors": []
}
}# Get settings
GET /api/v2/settings/general
# Update settings
PATCH /api/v2/settings/general
Content-Type: application/json
{
"site_name": "My PKI",
"default_validity_days": 365,
"require_approval": false
}# Get settings
GET /api/v2/settings/email
# Update settings
PATCH /api/v2/settings/email
Content-Type: application/json
{
"enabled": true,
"smtp_host": "smtp.example.com",
"smtp_port": 587,
"smtp_user": "[email protected]",
"smtp_password": "password",
"smtp_tls": true,
"from_address": "[email protected]"
}
# Test email
POST /api/v2/settings/email/test
Content-Type: application/json
{
"to": "[email protected]"
}# Get settings
GET /api/v2/settings/ldap
# Update settings
PATCH /api/v2/settings/ldap
Content-Type: application/json
{
"enabled": true,
"server": "ldap.example.com",
"port": 389,
"use_tls": true,
"base_dn": "dc=example,dc=com",
"bind_dn": "cn=admin,dc=example,dc=com",
"bind_password": "password"
}
# Test connection
POST /api/v2/settings/ldap/test# List webhooks
GET /api/v2/settings/webhooks
# Create webhook
POST /api/v2/settings/webhooks
Content-Type: application/json
{
"name": "Slack Notification",
"url": "https://hooks.slack.com/...",
"events": ["certificate_issued", "certificate_expiring"],
"secret": "webhook-secret"
}
# Test webhook
POST /api/v2/settings/webhooks/{webhook_id}/test
# Delete webhook
DELETE /api/v2/settings/webhooks/{webhook_id}# Get backup configuration
GET /api/v2/settings/backup
# Get backup schedule
GET /api/v2/settings/backup/schedule
# Update backup schedule
PATCH /api/v2/settings/backup/schedule
Content-Type: application/json
{
"enabled": true,
"frequency": "daily",
"time": "02:00",
"retention_days": 30
}
# Create backup
POST /api/v2/settings/backup/create
# List backups
GET /api/v2/settings/backup/history
# Download backup
GET /api/v2/settings/backup/{backup_id}/download
# Restore backup
POST /api/v2/settings/backup/restore
Content-Type: multipart/form-data
# Delete backup
DELETE /api/v2/settings/backup/{backup_id}# Get database stats
GET /api/v2/system/db/stats
# Export database
GET /api/v2/system/db/export
# Optimize database
POST /api/v2/system/db/optimize
# Check integrity
POST /api/v2/system/db/integrity-check
# Reset database (dangerous!)
POST /api/v2/system/db/reset
Content-Type: application/json
{
"confirm": true
}# Get current certificate info
GET /api/v2/system/https/cert-info
# Regenerate self-signed certificate
POST /api/v2/system/https/regenerate
Content-Type: application/json
{
"common_name": "ucm.example.com",
"validity_days": 365
}
# Apply new certificate
POST /api/v2/system/https/apply
Content-Type: application/json
{
"certificate": "-----BEGIN CERTIFICATE-----\n...",
"private_key": "-----BEGIN PRIVATE KEY-----\n..."
}# List backups
GET /api/v2/system/backup/list
# Create backup
POST /api/v2/system/backup/create
# Download backup
GET /api/v2/system/backup/{filename}/download
# Restore backup
POST /api/v2/system/backup/restore# Get chain repair status and last run stats
GET /api/v2/system/chain-repair
# Response:
{
"task": {
"name": "ski_aki_backfill",
"description": "Backfill SKI/AKI and repair certificate chain links",
"enabled": true,
"interval": 3600,
"last_run": "2026-02-12T01:51:14.502202Z",
"next_run": "2026-02-12T02:51:14.502204Z",
"run_count": 2,
"last_duration_ms": 9.2,
"last_error": null
},
"stats": {
"total_cas": 4,
"total_certs": 39,
"orphan_cas": 1,
"orphan_certs": 1,
"updated_cas": 0,
"updated_certs": 0,
"rechained_cas": 0,
"rechained_certs": 0,
"deduplicated": 0
}
}
# Trigger chain repair immediately
POST /api/v2/system/chain-repair/run
# Response: same as GET with updated statsGET /api/v2/system/security/encryption-statusResponse:
{
"data": {
"enabled": true,
"version": 1
}
}POST /api/v2/system/security/enable-encryption
Content-Type: application/json
{
"master_password": "secure-master-password"
}POST /api/v2/system/security/disable-encryption
Content-Type: application/json
{
"master_password": "secure-master-password"
}GET /api/v2/system/security/generate-keyResponse:
{
"data": {
"key": "generated-encryption-key"
}
}POST /api/v2/system/security/rotate-secrets
Content-Type: application/json
{
"new_key": "optional-new-key"
}GET /api/v2/system/security/secrets-statusResponse:
{
"data": {
"rotated_at": "2026-01-28T00:00:00",
"next_rotation": "2026-04-28T00:00:00"
}
}GET /api/v2/system/security/anomalies# Get rate limit settings
GET /api/v2/system/security/rate-limit
# Update rate limit settings
PUT /api/v2/system/security/rate-limit
Content-Type: application/json
{
"requests_per_minute": 100,
"enabled": true
}
# Get rate limit statistics
GET /api/v2/system/security/rate-limit/stats
# Reset rate limit counters
POST /api/v2/system/security/rate-limit/reset# Get retention settings
GET /api/v2/system/audit/retention
# Update retention settings
PUT /api/v2/system/audit/retention
Content-Type: application/json
{
"retention_days": 90
}
# Manual cleanup
POST /api/v2/system/audit/cleanup
Content-Type: application/json
{
"retention_days": 90
}# Get syslog settings
GET /api/v2/system/audit/syslog
# Update syslog settings
PUT /api/v2/system/audit/syslog
Content-Type: application/json
{
"host": "syslog.example.com",
"port": 514,
"protocol": "udp",
"enabled": true
}
# Test syslog connection
POST /api/v2/system/audit/syslog/test# Get alert configuration
GET /api/v2/system/alerts/expiry
# Update alert configuration
PUT /api/v2/system/alerts/expiry
Content-Type: application/json
{
"days": 30,
"enabled": true,
"recipients": ["[email protected]"]
}
# Trigger expiry check
POST /api/v2/system/alerts/expiry/check# Check for updates
GET /api/v2/system/updates/check
# Install update
POST /api/v2/system/updates/install
# Get current version
GET /api/v2/system/updates/versionResponse (version):
{
"data": {
"version": "2.1.0",
"build": "abc123",
"release_date": "2026-02-01"
}
}GET /api/v2/system/hsm-status# Get service status
GET /api/v2/system/service/status
# Restart service
POST /api/v2/system/service/restart
Content-Type: application/json
{
"service": "ucm"
}POST /api/v2/certificates/import
Content-Type: multipart/form-data
file: <certificate file> # Required: .pem, .crt, .cer, .der, .p12, .pfx
name: "My Certificate" # Optional: display name
password: "pkcs12password" # Optional: for PKCS12 files
ca_id: 1 # Optional: link to specific CA (auto-detected if omitted)
import_key: true # Optional: import private key (default: true)
# Response (201 Created)
{
"data": {
"id": 123,
"refid": "uuid",
"descr": "My Certificate",
"subject": "CN=example.com",
"issuer": "CN=My CA",
...
},
"message": "Certificate \"My Certificate\" imported successfully"
}
# If CA certificate detected (CA:TRUE basic constraint):
{
"data": { ... }, # CA object, not certificate
"message": "CA certificate \"My CA\" imported successfully (detected as CA)"
}Features:
- Auto-detects format: PEM, DER, PKCS12, PKCS7
- Handles PEM files with text before/after the certificate block
- Auto-detects CA certificates (CA:TRUE) and stores in CAs table
- Auto-links certificates to parent CA by issuer matching
POST /api/v2/cas/import
Content-Type: multipart/form-data
file: <CA certificate file> # Required
name: "My Root CA" # Optional: display name
password: "pkcs12password" # Optional: for PKCS12 files
import_key: true # Optional: import private key (default: true)
# Response (201 Created)
{
"data": {
"id": 5,
"refid": "uuid",
"descr": "My Root CA",
"subject": "CN=My Root CA,O=Org",
"is_root": true,
...
},
"message": "CA \"My Root CA\" imported successfully"
}# Test connection
POST /api/v2/import/opnsense/test
Content-Type: application/json
{
"host": "192.168.1.1",
"api_key": "...",
"api_secret": "..."
}
# Import certificates
POST /api/v2/import/opnsense/import
Content-Type: application/json
{
"host": "192.168.1.1",
"api_key": "...",
"api_secret": "...",
"import_cas": true,
"import_certificates": true
}POST /api/v2/tools/check-ssl
Content-Type: application/json
{
"hostname": "example.com",
"port": 443
}POST /api/v2/tools/decode-csr
Content-Type: application/json
{
"pem": "-----BEGIN CERTIFICATE REQUEST-----\n..."
}POST /api/v2/tools/decode-cert
Content-Type: application/json
{
"pem": "-----BEGIN CERTIFICATE-----\n..."
}POST /api/v2/tools/match-keys
Content-Type: application/json
{
"certificate": "-----BEGIN CERTIFICATE-----\n...",
"private_key": "-----BEGIN PRIVATE KEY-----\n...",
"csr": "-----BEGIN CERTIFICATE REQUEST-----\n...",
"password": "optional-key-password"
}POST /api/v2/tools/convert
Content-Type: application/json
{
"pem": "-----BEGIN CERTIFICATE-----\n...",
"input_type": "pem",
"output_format": "pkcs12",
"password": "output-password",
"pkcs12_password": "pkcs12-password",
"chain": "-----BEGIN CERTIFICATE-----\n...",
"private_key": "-----BEGIN PRIVATE KEY-----\n..."
}GET /api/v2/search?q=example.com&limit=20Query Parameters:
| Parameter | Type | Description |
|---|---|---|
q |
string | Search query (required) |
limit |
integer | Max results per category (default: 5) |
Response:
{
"data": {
"certificates": [...],
"cas": [...],
"csrs": [...],
"users": [...]
}
}GET /api/v2/groups
GET /api/v2/groups?search=engineeringPOST /api/v2/groups
Content-Type: application/json
{
"name": "Engineering",
"description": "Engineering team",
"permissions": ["read:certificates", "write:certificates"]
}GET /api/v2/groups/{group_id}PUT /api/v2/groups/{group_id}
Content-Type: application/json
{
"name": "Engineering",
"description": "Updated description",
"permissions": ["read:*", "write:certificates"]
}DELETE /api/v2/groups/{group_id}GET /api/v2/groups/{group_id}/membersPOST /api/v2/groups/{group_id}/members
Content-Type: application/json
{
"user_id": 5,
"role": "member"
}DELETE /api/v2/groups/{group_id}/members/{user_id}GET /api/v2/groups/statsPOST /api/v2/import/analyze
Content-Type: application/json
{
"content": "-----BEGIN CERTIFICATE-----\n...",
"password": "optional-password"
}Response:
{
"data": {
"type": "certificate",
"format": "pem",
"details": { ... }
}
}POST /api/v2/import/execute
Content-Type: application/json
{
"content": "-----BEGIN CERTIFICATE-----\n...",
"password": "optional-password",
"options": { ... }
}GET /api/v2/import/formatsGET /api/v2/dns-providersGET /api/v2/dns-providers/typesPOST /api/v2/dns-providers
Content-Type: application/json
{
"name": "Cloudflare",
"provider_type": "cloudflare",
"credentials": {
"api_token": "..."
},
"zones": ["example.com"],
"is_default": true,
"enabled": true
}GET /api/v2/dns-providers/{provider_id}PATCH /api/v2/dns-providers/{provider_id}
Content-Type: application/json
{
"name": "Updated Name",
"credentials": { "api_token": "new-token" },
"zones": ["example.com", "example.org"],
"enabled": true,
"is_default": false
}DELETE /api/v2/dns-providers/{provider_id}POST /api/v2/dns-providers/{provider_id}/testUCM can act as an ACME client to obtain certificates from Let's Encrypt and other ACME-compatible CAs. This is distinct from the ACME Server section, which covers UCM acting as its own ACME server.
GET /api/v2/acme/client/settingsPATCH /api/v2/acme/client/settings
Content-Type: application/json
{
"email": "[email protected]",
"environment": "production",
"renewal_enabled": true,
"renewal_days": 30
}GET /api/v2/acme/client/orders
GET /api/v2/acme/client/orders?status=pending&environment=productionGET /api/v2/acme/client/orders/{order_id}POST /api/v2/acme/client/request
Content-Type: application/json
{
"domains": ["example.com", "www.example.com"],
"email": "[email protected]",
"challenge_type": "dns-01",
"environment": "production",
"dns_provider_id": 1
}POST /api/v2/acme/client/orders/{order_id}/verify
Content-Type: application/json
{
"domain": "example.com"
}GET /api/v2/acme/client/orders/{order_id}/statusPOST /api/v2/acme/client/orders/{order_id}/finalizeDELETE /api/v2/acme/client/orders/{order_id}POST /api/v2/acme/client/orders/{order_id}/renewPOST /api/v2/acme/client/account
Content-Type: application/json
{
"email": "[email protected]",
"environment": "production"
}GET /api/v2/acme/domainsGET /api/v2/acme/domains/{domain_id}POST /api/v2/acme/domains
Content-Type: application/json
{
"domain": "example.com",
"dns_provider_id": 1,
"is_wildcard_allowed": true,
"auto_approve": false
}PUT /api/v2/acme/domains/{domain_id}
Content-Type: application/json
{
"dns_provider_id": 2,
"is_wildcard_allowed": false,
"auto_approve": true
}DELETE /api/v2/acme/domains/{domain_id}GET /api/v2/acme/domains/resolve?domain=example.comPOST /api/v2/acme/domains/test
Content-Type: application/json
{
"domain": "example.com",
"dns_provider_id": 1
}GET /api/v2/sso/providersGET /api/v2/sso/providers/{provider_id}
GET /api/v2/sso/providers/{provider_id}?include_secrets=truePOST /api/v2/sso/providers
Content-Type: application/json
{
"name": "corporate-ldap",
"provider_type": "ldap",
"display_name": "Corporate LDAP",
"icon": "ldap",
"enabled": true,
"default_role": "viewer",
"auto_create_users": true,
"auto_update_users": false
}Additional fields depend on provider_type (ldap, oauth2, saml).
PUT /api/v2/sso/providers/{provider_id}
Content-Type: application/json
{ ... }DELETE /api/v2/sso/providers/{provider_id}POST /api/v2/sso/providers/{provider_id}/togglePOST /api/v2/sso/providers/{provider_id}/testGET /api/v2/sso/sessionsGET /api/v2/sso/availableReturns enabled SSO providers for display on the login page. No authentication required.
GET /api/v2/sso/login/{provider_id}Redirects the user to the SSO provider's login page. No authentication required.
GET /api/v2/sso/callback/{provider_id}
POST /api/v2/sso/callback/{provider_id}Handles the SSO provider's callback after authentication. POST is used for SAML responses. No authentication required.
POST /api/v2/sso/ldap/login
Content-Type: application/json
{
"username": "jdoe",
"password": "ldap-password",
"provider_id": 1
}No authentication required.
GET /api/v2/hsm/providersPOST /api/v2/hsm/providers
Content-Type: application/json
{
"name": "YubiHSM",
"type": "yubihsm",
"config": {
"connector_url": "http://localhost:12345"
}
}GET /api/v2/hsm/providers/{provider_id}PUT /api/v2/hsm/providers/{provider_id}
Content-Type: application/json
{
"name": "Updated Name",
"config": { ... }
}DELETE /api/v2/hsm/providers/{provider_id}POST /api/v2/hsm/providers/{provider_id}/testPOST /api/v2/hsm/providers/{provider_id}/syncGET /api/v2/hsm/keys
GET /api/v2/hsm/keys?provider_id=1POST /api/v2/hsm/providers/{provider_id}/keys
Content-Type: application/json
{
"label": "ca-signing-key",
"algorithm": "RSA-2048",
"purpose": "signing",
"extractable": false
}GET /api/v2/hsm/keys/{key_id}DELETE /api/v2/hsm/keys/{key_id}GET /api/v2/hsm/keys/{key_id}/publicPOST /api/v2/hsm/keys/{key_id}/sign
Content-Type: application/json
{
"data": "base64-encoded-data",
"algorithm": "SHA256withRSA"
}GET /api/v2/hsm/provider-typesGET /api/v2/hsm/dependenciesPOST /api/v2/hsm/dependencies/install
Content-Type: application/json
{
"provider": "pkcs11"
}The /api/v2/webauthn/ blueprint provides the same WebAuthn credential management functionality as the /api/v2/account/webauthn/ routes. Both prefixes are available for convenience.
GET /api/v2/webauthn/credentialsDELETE /api/v2/webauthn/credentials/{credential_id}POST /api/v2/webauthn/credentials/{credential_id}/toggle
Content-Type: application/json
{
"enabled": true
}POST /api/v2/webauthn/register/optionsPOST /api/v2/webauthn/register/verify
Content-Type: application/json
{
"credential": { ... },
"name": "YubiKey 5"
}These routes are also accessible under /api/v2/settings/webhooks as an alias.
GET /api/v2/webhooksGET /api/v2/webhooks/{endpoint_id}POST /api/v2/webhooks
Content-Type: application/json
{
"name": "Slack Notification",
"url": "https://hooks.slack.com/...",
"secret": "webhook-secret",
"events": ["certificate_issued", "certificate_expiring"],
"ca_filter": [1, 2],
"enabled": true,
"custom_headers": {
"X-Custom": "value"
}
}PUT /api/v2/webhooks/{endpoint_id}
Content-Type: application/json
{
"name": "Updated Name",
"url": "https://hooks.slack.com/...",
"events": ["certificate_issued"],
"enabled": true
}DELETE /api/v2/webhooks/{endpoint_id}POST /api/v2/webhooks/{endpoint_id}/togglePOST /api/v2/webhooks/{endpoint_id}/testPOST /api/v2/webhooks/{endpoint_id}/regenerate-secretGET /api/v2/webhooks/eventsGET /api/v2/policiesGET /api/v2/policies/{policy_id}POST /api/v2/policies
Content-Type: application/json
{
"name": "Production Certificate Policy",
"description": "Requires approval for production certificates",
"policy_type": "issuance",
"ca_id": 2,
"template_id": 1,
"requires_approval": true,
"approval_group_id": 1,
"min_approvers": 2,
"notify_on_violation": true,
"is_active": true,
"priority": 10,
"rules": { ... },
"notification_emails": ["[email protected]"]
}PUT /api/v2/policies/{policy_id}
Content-Type: application/json
{ ... }DELETE /api/v2/policies/{policy_id}POST /api/v2/policies/{policy_id}/toggleGET /api/v2/approvals
GET /api/v2/approvals?status=pendingGET /api/v2/approvals/{request_id}POST /api/v2/approvals/{request_id}/approve
Content-Type: application/json
{
"comment": "Approved for production use"
}POST /api/v2/approvals/{request_id}/reject
Content-Type: application/json
{
"comment": "Missing justification"
}GET /api/v2/approvals/statsUCM provides 6 built-in report types, an executive PDF report, and a full report scheduler with email delivery.
Available Report Types:
| Type Key | Description |
|---|---|
expiring_certificates |
Certificates expiring within N days |
revoked_certificates |
All revoked certificates with revocation reason |
ca_hierarchy |
CA tree with issued certificate counts |
audit_summary |
Audit log activity grouped by action type |
compliance_status |
Policy compliance across all certificates |
certificate_inventory |
Full certificate inventory with metadata |
GET /api/v2/reports/typesResponse:
{
"data": [
{
"id": "expiring_certificates",
"name": "Expiring Certificates",
"description": "Certificates expiring within a specified number of days",
"params": ["days"]
},
{
"id": "revoked_certificates",
"name": "Revoked Certificates",
"description": "All revoked certificates with reason and date"
},
{
"id": "ca_hierarchy",
"name": "CA Hierarchy",
"description": "Certificate Authority tree with counts"
},
{
"id": "audit_summary",
"name": "Audit Summary",
"description": "Recent audit log activity by action type"
},
{
"id": "compliance_status",
"name": "Compliance Status",
"description": "Policy compliance overview"
},
{
"id": "certificate_inventory",
"name": "Certificate Inventory",
"description": "Full inventory of all certificates"
}
]
}POST /api/v2/reports/generate
Content-Type: application/json
{
"report_type": "expiring_certificates",
"params": {
"days": 30
}
}Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
report_type |
string | Yes | One of the 6 report type keys |
params.days |
integer | No | Look-ahead days (for expiring_certificates, default: 30) |
Response:
{
"data": {
"report_type": "expiring_certificates",
"generated_at": "2026-01-15T08:00:00Z",
"records": [ ... ],
"total": 12
}
}GET /api/v2/reports/executive-pdfReturns a downloadable PDF document containing:
- Cover page with organization name and generation date
- Executive summary with key metrics
- Risk assessment
- Certificate inventory breakdown
- Compliance status
- Lifecycle analysis
- CA infrastructure overview
- Recommendations
Response: application/pdf binary (Content-Disposition: attachment)
GET /api/v2/reports/scheduleResponse:
{
"data": {
"expiring_certificates": {
"enabled": true,
"frequency": "weekly",
"time": "08:00",
"day_of_week": 1,
"day_of_month": 1,
"recipients": ["[email protected]"],
"format": "csv"
},
"revoked_certificates": {
"enabled": false,
"frequency": "monthly",
"time": "09:00",
"day_of_week": 0,
"day_of_month": 1,
"recipients": [],
"format": "pdf"
}
}
}PUT /api/v2/reports/schedule
Content-Type: application/json
{
"report_type": "expiring_certificates",
"config": {
"enabled": true,
"frequency": "weekly",
"time": "08:00",
"day_of_week": 1,
"day_of_month": 1,
"recipients": ["[email protected]", "[email protected]"],
"format": "csv"
}
}Schedule Config Fields:
| Field | Type | Required | Description |
|---|---|---|---|
report_type |
string | Yes | One of the 6 report type keys |
config.enabled |
boolean | Yes | Enable or disable the schedule |
config.frequency |
string | Yes | daily, weekly, or monthly |
config.time |
string | Yes | Execution time in HH:MM (24-hour format) |
config.day_of_week |
integer | No | For weekly: 0 (Mon) – 6 (Sun) |
config.day_of_month |
integer | No | For monthly: 1 – 28 |
config.recipients |
array | Yes | Email addresses (max 50) |
config.format |
string | Yes | csv, json, or pdf |
POST /api/v2/reports/send-test
Content-Type: application/json
{
"report_type": "expiring_certificates",
"recipient": "[email protected]"
}Generates the report immediately and sends it to the specified recipient. Use this to verify email delivery and report content before enabling a schedule.
Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
report_type |
string | Yes | One of the 6 report type keys |
recipient |
string | Yes | Email address to send the test report to |
GET /api/v2/websocket/statusGET /api/v2/websocket/clientsPOST /api/v2/websocket/broadcast
Content-Type: application/json
{
"message": "System maintenance in 10 minutes",
"alert_type": "warning",
"severity": "medium"
}GET /api/v2/websocket/eventsThese endpoints are served at /api/v2/health (primary) with backward-compatible aliases at /api/health and /health. They do not require authentication and are intended for load balancers, monitoring systems, and frontend reconnection detection.
GET /api/v2/healthResponse:
{
"status": "ok",
"service": "ucm",
"version": "2.1.0",
"started_at": 1707123456.789,
"websocket": true
}| Field | Description |
|---|---|
status |
Always "ok" when the service is running |
service |
Service identifier ("ucm") |
version |
Current application version |
started_at |
Unix timestamp when the service started |
websocket |
Indicates whether the WebSocket (Socket.IO) server is initialized and ready to accept connections |
GET /api/v2/health/readyVerifies the application can serve traffic (database, filesystem). Returns 200 if ready, 503 if not.
Response:
{
"status": "ready",
"checks": {
"database": { "status": "ok" },
"filesystem": { "status": "ok" }
}
}GET /api/v2/health/liveReturns 200 if the application process is alive, regardless of dependency status.
Response:
{
"status": "alive",
"service": "ucm"
}| Code | Description |
|---|---|
| 200 | Success |
| 201 | Created |
| 204 | No Content (successful deletion) |
| 400 | Bad Request (invalid parameters) |
| 401 | Unauthorized (not authenticated) |
| 403 | Forbidden (insufficient permissions) |
| 404 | Not Found |
| 409 | Conflict (resource already exists) |
| 422 | Unprocessable Entity (validation error) |
| 500 | Internal Server Error |
- Default: 100 requests per minute per IP
- Auth endpoints: 10 requests per minute per IP
- Export endpoints: 10 requests per minute per user
| Permission | Description |
|---|---|
* |
Full access (admin only) |
read:* |
Read access to all resources |
read:certificates |
Read certificates |
write:certificates |
Create/update certificates |
delete:certificates |
Delete/revoke certificates |
read:cas |
Read CAs |
write:cas |
Create/update CAs |
delete:cas |
Delete CAs |
read:users |
Read users |
write:users |
Create/update users |
delete:users |
Delete users |
read:audit |
View audit logs |
delete:audit |
Cleanup audit logs |
admin:system |
System administration |
# Login and save cookie
# Replace localhost with your server FQDN for remote access
curl -sk -c cookies.txt \
-X POST https://localhost:8443/api/v2/auth/login/password \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"changeme123"}'
# Use cookie for subsequent requests
curl -sk -b cookies.txt https://localhost:8443/api/v2/certificatesimport requests
# Login
session = requests.Session()
session.verify = False # For self-signed certs
response = session.post('https://localhost:8443/api/v2/auth/login/password',
json={'username': 'admin', 'password': 'changeme123'})
# List certificates
certs = session.get('https://localhost:8443/api/v2/certificates')
print(certs.json())// Login
const login = await fetch('/api/v2/auth/login/password', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: 'changeme123' }),
credentials: 'include'
});
// List certificates
const certs = await fetch('/api/v2/certificates', {
credentials: 'include'
});
const data = await certs.json();Documentation generated: February 2026
API Version: 2.2.x
Total Endpoints: ~276