API
Deniable encryption as a service. Register for a key, encrypt in one call.
Authentication
All endpoints (except registration and health) require a Bearer token:
Authorization: Bearer dk_your_api_key_here
Get an API key
POST /api/register
{
"email": "you@example.com",
"name": "My App" // optional
}
→ 201
{
"key": "dk_abc123...",
"tier": "free",
"monthly_limit": 100,
"message": "Store your API key securely."
}
One key per email. If you've already registered, you'll get a 409 response. Store your key when you first receive it.
Encrypt
POST /api/encrypt
{
"message": "launch codes: 38.8977° N, 77.0365° W",
"password1": "correct-horse",
"password2": "battery-staple"
}
→ 200
{
"ciphertext": "a3f2...hex",
"controlData": "b7c1...hex"
}
Store both the ciphertext and control data. You need the control data to decrypt or create decoys.
Decrypt
POST /api/decrypt
{
"ciphertextHex": "a3f2...hex",
"controlDataHex": "b7c1...hex",
"password1": "correct-horse",
"password2": "battery-staple"
}
→ 200
{
"message": "launch codes: 38.8977° N, 77.0365° W"
}
Create decoy
This is the core feature. Generate new control data that makes the same ciphertext decrypt to a completely different message.
POST /api/deny
{
"ciphertextHex": "a3f2...hex",
"password1": "correct-horse",
"password2": "battery-staple",
"fakeMessage": "grocery list: milk, eggs, bread"
}
→ 200
{
"controlData": "d4e5...hex"
}
// Now decrypt the SAME ciphertext with the new control data:
POST /api/decrypt
{
"ciphertextHex": "a3f2...hex", // same ciphertext
"controlDataHex": "d4e5...hex", // new control data
"password1": "correct-horse",
"password2": "battery-staple"
}
→ 200
{
"message": "grocery list: milk, eggs, bread" // different truth
}
Check usage
GET /api/usage
→ 200
{
"tier": "free",
"calls_this_month": 42,
"limit": 100,
"remaining": 58,
"resets_at": "2026-05-01T00:00:00.000Z"
}
Pricing
| Free | Dev - $19/mo | Pro - $49/mo | |
|---|---|---|---|
| Monthly calls | 100 | 10,000 | 100,000 |
| Endpoints | All | All | All |
| Support | GitHub | Priority |
To upgrade, email hello@deny.sh
Errors
All errors return JSON with an error field:
{ "error": "Missing or invalid API key" } // 401
{ "error": "Monthly limit reached" } // 429
{ "error": "Required: message, password1..." } // 400
{ "error": "Decryption failed: ..." } // 400