API Documentation
Monitor your SSL certificates programmatically with the StableSSL API
1. Get an API Key
API access is available on the Max plan. To create an API key:
- Upgrade to the Max plan
- Go to Account Settings → API Keys
- Click "Create API Key"
- Give your key a name and set an expiry period
- Save the key immediately - it will only be shown once!
2. Authentication
All API requests require authentication using your API key in the X-API-Key header:
X-API-Key: YOUR_API_KEY_HERE3. Base URL
https://api.stablessl.com/v14. Response Format
All responses are in JSON format with appropriate HTTP status codes.
| Code | Status | Description |
|---|---|---|
0 | Not Checked | Domain added but not yet checked |
1 | Active | Certificate valid, ≥30 days until expiry |
2 | Expiring Soon | Certificate expires in <30 days |
3 | Expired | Certificate has expired |
4 | Invalid DNS | DNS resolution failed (reserved) |
5 | Connection Error | Failed to connect and fetch certificate |
API Endpoints
Description
Returns a list of supported protocols. Use the protocol ID when creating or updating domains. Common protocols include HTTPS (port 443), FTPS (port 990), SMTPS (port 465).
Authentication
Required - Use API key in X-API-Key header
Response Example
[
{
"id": 1,
"name": "HTTPS"
},
{
"id": 2,
"name": "FTPS"
},
{
"id": 3,
"name": "SMTPS"
}
]Description
Returns a list of all domains you're monitoring with their SSL certificate status and expiry information.
Authentication
Required - Use API key in X-API-Key header
Response Example
[
{
"id": 1,
"host": "example.com",
"port": 443,
"protocol": 1,
"status": 1,
"notes": "Production server",
"agent": {
"id": 10,
"name": "Hoth"
},
"expiry_date": "2025-12-31T23:59:59Z",
"days_left": 350,
"last_check": "2025-01-15T10:30:00Z"
}
]Response Codes
200- Success401- Unauthorized (invalid API key)
Description
Add a new domain to monitor. Domain limits are enforced based on your plan (Free: 3, Pro: 20, Max: 50).
Authentication
Required - Use API key in X-API-Key header
Request Body
{
"host": "example.com",
"port": 443,
"protocol": 1,
"notes": "Production server",
"agent_id": 10
}Parameters
| Field | Type | Required | Description |
|---|---|---|---|
host | string | Domain hostname (e.g., example.com) | |
port | integer | Port number (1-65535) | |
protocol | integer | Protocol ID from /protocols endpoint | |
notes | string | Optional notes or comments | |
agent_id | integer | Agent ID for checking. Null or omitted = auto-assign |
Response Example
{
"id": 42,
"host": "example.com",
"port": 443,
"protocol": 1,
"status": 0,
"notes": "Production server",
"agent": {
"id": 10,
"name": "Hoth"
},
"expiry_date": null,
"days_left": 0,
"last_check": null
}Response Codes
201- Domain created successfully400- Invalid request (validation failed)401- Unauthorized (invalid API key)403- Forbidden (domain limit reached)409- Conflict (domain already exists)
Description
Retrieve details for a specific domain. Only domain owners can access their domains.
Authentication
Required - Use API key in X-API-Key header
Path Parameters
domain_id(integer) - The domain identifier
Response Example
{
"host": "example.com",
"port": 443,
"protocol": 1,
"status": 1,
"notes": "Production server",
"agent_id": 10
}Response Codes
200- Success401- Unauthorized (invalid API key)404- Domain not found
Description
Update a domain's host, port, or protocol. Only the domain owner can update it.
Authentication
Required - Use API key in X-API-Key header
Path Parameters
domain_id(integer) - The domain identifier
Request Body
{
"host": "newdomain.com",
"port": 8443,
"protocol": 1,
"notes": "Staging server",
"agent_id": 10
}Response Example
{
"host": "newdomain.com",
"port": 8443,
"protocol": 1,
"status": 0,
"notes": "Staging server",
"agent_id": 10
}Response Codes
200- Domain updated successfully400- Invalid request (validation failed)401- Unauthorized (invalid API key)404- Domain not found
Description
Permanently delete a domain from monitoring. This action cannot be undone. Only the domain owner can delete it.
Authentication
Required - Use API key in X-API-Key header
Path Parameters
domain_id(integer) - The domain identifier
Response Codes
200- Domain deleted successfully401- Unauthorized (invalid API key)404- Domain not found
Description
Retrieve historical certificate data for a domain. Returns certificates ordered by collection time (newest first). History depth is limited by your plan: Free (0 days), Pro (90 days), Max (180 days). Only domain owners can access history.
Authentication
Required - Use API key in X-API-Key header
Path Parameters
domain_id(integer) - The domain identifier
Response Example
[
{
"id": 123,
"domain_id": 1,
"fingerprint_sha256": "A1:B2:C3:...",
"subject": "CN=example.com",
"issuer": "CN=Let's Encrypt Authority X3",
"serial_number": "03:AF:...",
"not_before": "2024-01-01T00:00:00Z",
"not_after": "2024-04-01T00:00:00Z",
"signature_algorithm": "sha256WithRSAEncryption",
"key_type": "RSA",
"collected_at": "2024-01-15T10:30:00Z"
}
]Response Codes
200- Success401- Unauthorized (invalid API key)403- Forbidden (plan does not include certificate history)404- Domain not found or doesn't belong to user
Description
Retrieve complete details of a specific certificate including the full PEM certificate data. Only domain owners can access certificate details. Useful for detailed inspection and verification.
Authentication
Required - Use API key in X-API-Key header
Path Parameters
certificate_id(integer) - The certificate identifier
Response Example
{
"id": 123,
"domain_id": 1,
"fingerprint_sha256": "A1:B2:C3:D4:E5:F6:...",
"subject": "CN=example.com",
"issuer": "CN=Let's Encrypt Authority X3, O=Let's Encrypt, C=US",
"serial_number": "03:AF:12:34:56:...",
"not_before": "2024-01-01T00:00:00Z",
"not_after": "2024-04-01T00:00:00Z",
"signature_algorithm": "sha256WithRSAEncryption",
"key_type": "RSA",
"key_size": 2048,
"collected_at": "2024-01-15T10:30:00Z",
"hostname": "example.com",
"port": 443,
"protocol": "HTTPS",
"pem_certificate": "-----BEGIN CERTIFICATE-----\nMIIFZTCCBE2gAwIBAgISA...\n-----END CERTIFICATE-----"
}Response Codes
200- Success401- Unauthorized (invalid API key)404- Certificate not found or doesn't belong to user's domain
List all domains (cURL)
curl -X GET https://api.stablessl.com/v1/domains \
-H "X-API-Key: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json"Create a domain (cURL)
curl -X POST https://api.stablessl.com/v1/domains \
-H "X-API-Key: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"host": "example.com",
"port": 443,
"protocol": 1
}'List all domains (Python)
import requests
API_KEY = "YOUR_API_KEY_HERE"
BASE_URL = "https://api.stablessl.com/v1"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
}
response = requests.get(f"{BASE_URL}/domains", headers=headers)
domains = response.json()
for domain in domains:
print(f"{domain['host']}:{domain['port']} - Status: {domain['status']}")Create a domain (Python)
import requests
API_KEY = "YOUR_API_KEY_HERE"
BASE_URL = "https://api.stablessl.com/v1"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
}
data = {
"host": "example.com",
"port": 443,
"protocol": 1
}
response = requests.post(f"{BASE_URL}/domains", headers=headers, json=data)
if response.status_code == 201:
domain = response.json()
print(f"Domain created: {domain['id']}")
else:
print(f"Error: {response.status_code} - {response.text}")Get certificate history (cURL)
curl -X GET https://api.stablessl.com/v1/certificates/domain/123 \
-H "X-API-Key: YOUR_API_KEY_HERE" \
-H "Content-Type: application/json"Get certificate details (Python)
import requests
API_KEY = "YOUR_API_KEY_HERE"
BASE_URL = "https://api.stablessl.com/v1"
headers = {
"X-API-Key": API_KEY,
"Content-Type": "application/json"
}
# Get certificate details including PEM data
cert_id = 456
response = requests.get(f"{BASE_URL}/certificates/{cert_id}", headers=headers)
if response.status_code == 200:
cert = response.json()
print(f"Certificate for: {cert['subject']}")
print(f"Expires: {cert['not_after']}")
print(f"Fingerprint: {cert['fingerprint_sha256']}")
# Access PEM certificate data
pem_data = cert['pem_certificate']
else:
print(f"Error: {response.status_code} - {response.text}")Security
- Never commit API keys to version control
- Use environment variables to store API keys
- Rotate keys regularly (create new key, update apps, delete old key)
- Use separate keys for different environments (dev, staging, production)
- Deactivate or delete compromised keys immediately
Error Handling
- Always check HTTP status codes
- Implement exponential backoff for failed requests
- Handle 401 errors by checking if your API key is valid and not expired
- Handle 403 errors by verifying your plan includes the requested feature
- Handle 429 errors by reducing request frequency
Domain Limits
Respect your plan's domain limits:
- Free plan: 3 domains
- Pro plan: 20 domains
- Max plan: 50 domains