API¶
Base URL: https://your-instance.com/api/v1
Interactive docs are available on any running instance: Swagger UI at /docs, ReDoc at /redoc.
POST /pastes¶
Create a paste. Content must be pre-encrypted client-side (AES-256-GCM).
Request body¶
| Field | Type | Required | Description |
|---|---|---|---|
content |
string | Yes | Base64 AES-256-GCM ciphertext |
nonce |
string | Yes | Base64 12-byte GCM nonce |
kdf_salt |
string | No | Base64 PBKDF2 salt — present only for password-protected pastes |
language |
string | No | Language hint for syntax highlighting |
expires_in |
integer | No | TTL in seconds (≥ 1) |
burn |
boolean | No | Delete after first view. Default: false |
max_views |
integer | No | Delete after N views (≥ 1) |
webhook_url |
string | No | URL to POST on each read |
Response 201¶
Save the delete token
The delete_token is shown only once. Append it to the URL fragment to enable the delete button in the UI.
GET /pastes/{id}¶
Fetch a paste. This counts as a view — burn and max_views are evaluated server-side.
Response 200¶
Errors¶
| Code | Reason |
|---|---|
404 |
Paste not found, expired, or already burned |
DELETE /pastes/{id}¶
Delete a paste using the token issued at creation.
Response¶
| Code | Meaning |
|---|---|
204 |
Deleted |
403 |
Invalid token |
404 |
Paste not found |
422 |
Missing X-Delete-Token header |
POST /detect¶
Detect the language of a plaintext snippet. Used by the UI for auto-detection.
Response 200¶
Returns null if the snippet is too short or the language cannot be determined.
Webhook payload¶
When webhook_url is set, Ghostbit sends a POST request on each view:
The request has a 5-second timeout and is fire-and-forget (failures are not retried).
Webhook signature¶
If WEBHOOK_SECRET is configured on the server, every delivery includes an HMAC-SHA256 signature and a timestamp:
The timestamp header is always sent (even without WEBHOOK_SECRET) and mirrors payload.timestamp — use it to reject stale replays (~5 min window) without parsing the body. The signature is computed over the raw JSON body. Verify it on the receiving end:
Always use constant-time comparison to prevent timing attacks. See the Encryption page for more details and Node.js examples.