API & Webhooks

Integrate SchlüsselBot securely into your own software.

The Business API can create messages, check delivery status, withdraw open sendings, and manage contacts. Webhooks reliably notify your software of important state changes.

Download OpenAPI 3.1AI product knowledgeRights & copyright
Granular rights Each key receives only the scopes actually required by its application.
Browser-enabled Up to ten exact HTTPS origins can be granted CORS access per key.
Reliable events Webhooks are first queued and automatically retried with controlled handling in case of errors.

Quick start

Create a key in your account under Interface & Webhooks. It will be displayed in full only once. SchlüsselBot stores only its checksum.

curl -X POST https://schluesselbot.de/v1/messages \
  -H "Authorization: Bearer sb_live_XXXXXXXX_…" \
  -H "Idempotency-Key: auftrag-4711-versand-1" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient_email": "empfaenger@firma.de",
    "message": "Zugang: kunde42 / T7!kq2wZ",
    "ttl_hours": 48,
    "sender_name": "Kanzlei Weber"
  }'

For server-to-server calls, the Bearer token is sufficient. External browser applications additionally require an origin approved by the key, for example https://portal.firma.de.

Important for browser applications: CORS prevents calls from unapproved websites, but does not make a JavaScript-built API key secret. Use a narrowly scoped key and protect the application against XSS. For publicly distributed frontend JavaScript, using a dedicated backend as intermediary is the more secure architecture.

Permissions

ScopeAllowed
messages:sendSend messages and already client-side encrypted attachments
messages:readCheck the status of your own API dispatch
messages:withdrawPermanently block and remove an outstanding, own message
contacts:readRead and search your own contacts
contacts:writeCreate, edit, and delete your own contacts

Messages

POST/v1/messagesScope messages:send

/v1/send remains available as a compatible alias. When using automated retries, always use a unique Idempotency-Key. The same key with identical content returns the same response within 24 hours; different content results in HTTP 409.

Two encryption paths: With message, the plaintext briefly reaches the SchlüsselBot memory and is encrypted there. For provider blindness, your application encrypts itself, sends ciphertext, and distributes the key separately using delivery_mode: "separate". A transmitted fragment enables automatic email delivery, but still reaches the server.
FieldMandatoryContent
recipient_emailyesRecipient address
messagealternativePlain text up to 256 KB, encrypted on server side in storage
ciphertextalternativeBase64: 12-byte nonce + AES-256-GCM ciphertext + 16-byte tag
fragmentfor automatic delivery32-byte key as 43-character base64url without padding
attachment_ciphertextnoAlready encrypted file container, up to 100 MB of raw data
delivery_modenoautomatic or separate
ttl_hoursno1 to 168, default 48
sender_namenoDisplay name up to 80 characters
personal_notenoEmail note up to 500 characters; external links are removed
notify_emailnoE-Mail for delivery confirmation after retrieval
{
  "id": "8f3c…",
  "link": "https://schluesselbot.de/r/8f3c…#kQ2…",
  "expires_at": "2026-08-20T09:00:00+00:00",
  "modus": "encrypted by the server",
  "delivery": "automatic",
  "mail_sent": true,
  "has_attachment": false
}
GET/v1/messages/{id}Scope messages:read

Returns ready , consumed , withdrawn , expired , or unknown if the safe cannot currently be verified. A failure is never falsely reported as a retrieval.

DELETE/v1/messages/{id}Scope messages:withdraw

First permanently locks the transaction and then removes it from the vault. If physical deletion temporarily fails, the message remains inaccessible and cleanup will automatically be retried.

Contacts

Contact names and email addresses are encrypted in the database using AES-256-GCM. API responses are not cached.

MethodPathScopeFunction
GET/v1/contacts?q=&cursor=&limit=contacts:readSearch and list page by page, up to 100 per page
POST/v1/contactscontacts:write{"name":"Anna","email":"anna@example.de"}
GET/v1/contacts/{id}contacts:readLoad single contact
PATCH/v1/contacts/{id}contacts:writeName or address partially changed
DELETE/v1/contacts/{id}contacts:writeDelete contact

Webhooks

Selectable events: created, consumed, withdrawn, expired, and delivery_failed. SchlüsselBot permanently stores each event prior to the first delivery attempt. An HTTP 2xx response is expected within five seconds. In case of failure, up to eight retries will occur over approximately three days: after 1 minute, 5 minutes, 15 minutes, 1 hour, and then at increasing intervals.

{
  "api_version": "v1",
  "event_id": "consumed:8f3c…",
  "event": "consumed",
  "zeit": "2026-08-19T10:12:33+00:00",
  "daten": {"id": "8f3c…", "mit_anhang": false}
}
X-SchluesselBot-Event: consumed
X-SchluesselBot-Event-Id: consumed:8f3c…
X-SchluesselBot-Delivery: wd_…
X-SchluesselBot-Signature: sha256=<HMAC-SHA256 des unveränderten Roh-Rumpfs>

Verify the signature over the unmodified request body and process event_id idempotently. The secret is shown once upon creation and stored separately by SchlüsselBot, AES-256-GCM encrypted.

// PHP
$expected = 'sha256=' . hash_hmac('sha256', $rawBody, $webhookSecret);
if (!hash_equals($expected, $_SERVER['HTTP_X_SCHLUESSELBOT_SIGNATURE'] ?? '')) {
    http_response_code(401); exit;
}

Webhook targets must be publicly reachable, HTTPS, and without redirection. Private, loopback, link-local, documentation, and Tailscale/CGNAT networks are blocked; the resolved public IP is permanently fixed for the actual connection setup.

Errors and limitations