API Documentation
Integrate Burn the Secret into your applications to create secure, self-destructing secret links programmatically.
Base URL
https://burnthesecret.com/apiAES-256-GCM Encryption
Industry-standard authenticated encryption used by banks and governments.
Zero-Knowledge Architecture
Decryption keys never touch our servers. Your secrets stay secret.
Self-Destructing Links
Set view limits and expiration times. Secrets auto-delete after access.
RESTful JSON API
Simple HTTP endpoints with consistent response formats.
Authentication
All API requests require authentication using an API key. Include your key in the Authorization header:
Authorization: Bearer ks_live_your_api_keyCreate API keys in your Dashboard → API Access. Requests without a valid API key receive a 401 Unauthorized response.
Quick Start
Create a secret link with a single API call:
curl -X POST https://burnthesecret.com/api/secrets \
-H "Authorization: Bearer ks_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"text": "my-sensitive-password", "ttl": 86400, "maxViews": 1}'Endpoints
/secretsAuth RequiredCreate a new secret link.
Request Body
| Parameter | Type | Description |
|---|---|---|
| text | string | object | Secret content (max 50MB). Plain string or {ciphertext, iv} |
| ttl | number | Time to live in seconds. 1800-604800. Default: 86400 |
| maxViews | number | null | Max views (1-100) or null for unlimited. Default: 1 |
| passphrase | string | Optional passphrase protection (min 4 chars) |
| files | array | Array of files with filename, mimeType, data |
Response
{
"success": true,
"secretUrl": "https://burnthesecret.com/secret/Kj8mNp2x...#key=...",
"metadataUrl": "https://burnthesecret.com/receipt/Yz3nLq9b...",
"metadata": {
"key": "Yz3nLq9bFs7hGc...",
"secretKey": "Kj8mNp2xQr5tVw...",
"expiresAt": "2026-01-27T12:00:00.000Z",
"maxViews": 1
}
}/secrets/:keyCheck if a secret exists and get metadata. Does not consume a view.
{
"exists": true,
"type": "secret",
"hasPassphrase": false,
"expiresAt": "2026-01-27T12:00:00.000Z",
"maxViews": 1,
"viewsRemaining": 1
}/secrets/:secretKeyRetrieve secret content. This consumes one view.
Request Body (if passphrase protected)
{ "passphrase": "your-passphrase" }Response
{
"success": true,
"text": {
"ciphertext": "base64-encoded...",
"iv": "base64-encoded..."
},
"viewsRemaining": 0
}Decrypt using the key from the URL fragment with AES-256-GCM.
/secrets/:keyPermanently delete (burn) a secret.
curl -X DELETE https://burnthesecret.com/api/secrets/Yz3nLq9bFs7hGc...
Encryption
Burn the Secret uses AES-256-GCM, the same encryption used by TLS 1.3, Signal, and government systems.
Zero-Knowledge Architecture
The decryption key is stored in the URL fragment (after #), which browsers never send to servers. We only store encrypted ciphertext—useless without the key. Decryption happens entirely in the recipient's browser.
URL Structure:
https://burnthesecret.com/secret/secretKey#key=decryptionKeyServer-Side Encryption
Send plaintext—we encrypt it and return the URL with the key in the fragment.
Client-Side Encryption
Encrypt before sending—you control the key. Maximum security.
Rate Limits
1,000 requests per hour per API key using a sliding-window algorithm.
Response Headers
X-RateLimit-Limit: 1000 X-RateLimit-Remaining: 950 X-RateLimit-Reset: 1706360400
Errors
All errors return a consistent JSON structure:
{
"success": false,
"error": "INVALID_PASSPHRASE",
"message": "Invalid passphrase",
"hint": "Include the correct passphrase in your request.",
"requestId": "req_abc123..."
}| Status | Code | Description |
|---|---|---|
| 200 | — | Success |
| 400 | INVALID_* | Bad request (invalid params) |
| 401 | UNAUTHORIZED | Missing/invalid API key |
| 403 | INVALID_PASSPHRASE | Wrong passphrase |
| 404 | NOT_FOUND | Secret not found |
| 410 | SECRET_EXPIRED | Expired/burned/max views |
| 429 | TOO_MANY_ATTEMPTS | Rate limit exceeded |
| 500 | INTERNAL_ERROR | Server error |
For security, 404 is returned for any inaccessible secret regardless of reason.
Security Best Practices
Choose the Right Encryption Mode
- Server-side: Convenient—we handle encryption. Plaintext briefly in memory.
- Client-side: Maximum security—you control the key entirely.
Passphrase Tips
Use 8+ characters with mixed case, numbers, symbols. Share passphrases via a different channel than the URL.
Minimize Exposure
Use the shortest TTL and lowest maxViews needed. For one-time credentials, use maxViews: 1.
Code Examples
Decrypting Retrieved Secrets
JavaScript
const urlKey = window.location.hash.split('key=')[1];
const rawKey = Uint8Array.from(
atob(urlKey.replace(/-/g, '+').replace(/_/g, '/')),
c => c.charCodeAt(0)
);
const key = await crypto.subtle.importKey(
'raw', rawKey, { name: 'AES-GCM' }, false, ['decrypt']
);
const ciphertext = Uint8Array.from(atob(response.text.ciphertext), c => c.charCodeAt(0));
const iv = Uint8Array.from(atob(response.text.iv), c => c.charCodeAt(0));
const plaintext = await crypto.subtle.decrypt(
{ name: 'AES-GCM', iv }, key, ciphertext
);
const secret = new TextDecoder().decode(plaintext);Python
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import base64
key = base64.urlsafe_b64decode(url_key + '==')
ciphertext = base64.b64decode(response['text']['ciphertext'])
iv = base64.b64decode(response['text']['iv'])
aesgcm = AESGCM(key)
plaintext = aesgcm.decrypt(iv, ciphertext, None)
secret = plaintext.decode('utf-8')Client-Side Encryption
For maximum security, encrypt before sending to Burn the Secret:
JavaScript
// Generate key and IV
const key = await crypto.subtle.generateKey(
{ name: 'AES-GCM', length: 256 }, true, ['encrypt']
);
const iv = crypto.getRandomValues(new Uint8Array(12));
// Encrypt
const plaintext = new TextEncoder().encode('my-secret');
const ciphertext = await crypto.subtle.encrypt(
{ name: 'AES-GCM', iv }, key, plaintext
);
// Export key for URL
const rawKey = await crypto.subtle.exportKey('raw', key);
const keyBase64 = btoa(String.fromCharCode(...new Uint8Array(rawKey)));
// Send to API
const response = await fetch('https://burnthesecret.com/api/secrets', {
method: 'POST',
headers: {
'Authorization': 'Bearer ks_live_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({
text: {
ciphertext: btoa(String.fromCharCode(...new Uint8Array(ciphertext))),
iv: btoa(String.fromCharCode(...iv))
}
})
});
const data = await response.json();
const fullUrl = data.secretUrl + '#key=' + keyBase64;