Reference
On this page
API reference
Everything in the web UI is available over a JSON REST API at https://testlie.com/api.
Authentication
Create an API key on the API keys page (owners and admins). Keys start with tl_, belong to one team, and are shown once: Testlie stores only a SHA-256 hash. Send the key as a bearer token:
curl -H "Authorization: Bearer tl_..." https://testlie.com/api/inboxes| Key option | Effect |
|---|---|
Access write (default) |
Acts as a team admin for projects, inboxes, messages, webhooks, forwarding and identity providers. |
Access read |
Only GET requests; anything else answers 403 with "code": "read_only_key". Use it for tests that only wait for and read mail. |
| Expiry | Optional, 1 to 3650 days. An expired key answers 401 with "code": "api_key_expired". |
Team membership, team SSO, API keys and the audit log need a signed-in person; keys cannot manage keys. The web UI uses the same endpoints with its session cookie.
Errors
Errors are JSON with a 4xx or 5xx status:
{ "error": "Inbox not found" }| Status | Meaning |
|---|---|
400 |
Invalid request; validation errors include an issues array. |
401 |
Missing, unknown or expired API key, or not signed in. |
402 |
A plan limit was reached or the plan lacks the feature: { "error", "code": "quota_exceeded" | "feature_unavailable", "limit", "upgradeUrl" }. |
403 |
The key is read-only, or the action needs an admin or a signed-in person. |
404 |
Not found, or it belongs to another team. |
408 |
messages/wait timed out. |
429 |
Rate limited; try again shortly. |
Inboxes and projects
| Method and path | Description |
|---|---|
GET, POST /api/projects |
List or create projects ({ "name" }) |
PATCH, DELETE /api/projects/:id |
Rename or delete a project (its inboxes are kept) |
GET /api/inboxes |
List inboxes with message and unread counts and SMTP credentials |
POST /api/inboxes |
Create an inbox: { "name", "maxMessages"?, "projectId"?, "expiresInMinutes"? }. expiresInMinutes (up to 10080) makes it disposable |
GET, PATCH, DELETE /api/inboxes/:id |
Read, update (name, maxMessages, projectId) or delete an inbox |
POST /api/inboxes/:id/credentials |
Rotate the inbox's SMTP password |
POST /api/inboxes/:id/test-message |
Store a sample HTML email (with an inline image) in the inbox. Counts toward the monthly quota; at most 10 per inbox per minute |
GET /api/inboxes/:id/events |
Server-sent events stream: message.created, message.updated, message.deleted, inbox.updated |
GET, PUT /api/inboxes/:id/forwarding |
Automatic forwarding: { "enabled", "to": [...], "match"? } (recipients must be verified) |
Messages
| Method and path | Description |
|---|---|
GET /api/inboxes/:id/messages |
List messages, newest first: q (search subject, sender, recipients), unread=true, page, limit (max 200). Returns { total, page, limit, messages } |
PATCH /api/inboxes/:id/messages |
Mark every message read |
DELETE /api/inboxes/:id/messages |
Empty the inbox |
GET /api/inboxes/:id/messages/wait |
Long-poll for a message: to, subject (contains), since (ISO time), timeout (1-120 s, default 30). 200 with { message }, or 408 on timeout. See Testing in CI |
GET /api/messages/:id |
Full message: subject, from, to, cc, bcc, envelope, html, text, headers, size, attachments |
PATCH, DELETE /api/messages/:id |
Mark read or unread ({ "isRead" }), or delete |
GET /api/messages/:id/raw |
Original MIME; ?download=1 for an .eml file |
GET /api/messages/:id/html |
Sandboxed HTML rendering used by the preview |
GET /api/messages/:id/preview-url |
A signed URL for the preview, valid 15 minutes, for embedding it where there is no session |
GET /api/messages/:id/attachments/:attachmentId |
Download an attachment |
GET /api/messages/:id/spam |
Spam score and rules |
GET /api/messages/:id/html-check |
Email-client compatibility report |
POST /api/messages/:id/forward |
Forward to verified addresses ({ "to": [...] }, up to 10) |
Forwarding addresses
| Method and path | Description |
|---|---|
GET /api/forward-addresses |
The team's forwarding addresses, with verifiedAt |
POST /api/forward-addresses |
Add an address ({ "email" }) and email it a confirmation link; resends for an unverified address |
DELETE /api/forward-addresses/:id |
Remove an address (also from automatic forwarding) |
GET /api/forwarding-status |
Whether the server can send mail (outboundEnabled) and the recipient limit |
Webhooks
| Method and path | Description |
|---|---|
GET, POST /api/webhooks |
List or create webhooks ({ "url", "inboxId"?, "events"?, "enabled"? }). The signing secret is returned to admins |
PATCH, DELETE /api/webhooks/:id |
Update or delete a webhook |
POST /api/webhooks/:id/test |
Send a signed webhook.test event now and return the result |
GET /api/webhooks/:id/deliveries |
Delivery log, newest first (limit, max 200; kept 30 days) |
POST /api/webhooks/:id/deliveries/:deliveryId |
Redeliver an earlier event |
See Webhooks for the payload and signature.
Mock identity providers
| Method and path | Description |
|---|---|
GET, POST /api/idps |
List or create mock identity providers ({ "name", "redirectUris"? }) |
GET, PATCH, DELETE /api/idps/:id |
Read, update (redirectUris, postLogoutRedirectUris, tokenTtl, autoLoginUserId, requireTeamSession, samlAcsUrl, samlSpEntityId, samlNameIdFormat) or delete an IdP |
POST /api/idps/:id/rotate |
Rotate the client secret ({ "what": "secret" }) or signing key ({ "what": "keys" }) |
GET, POST /api/idps/:id/users |
List or add test users ({ "email", "name", "groups"?, "claims"?, "subject"? }) |
PATCH, DELETE /api/idps/:id/users/:userId |
Update or remove a test user |
GET, DELETE /api/idps/:id/events |
Activity log, newest first (after, limit), or clear it |
The IdPs' own protocol endpoints (/idp/<slug>/...) are listed in Mock identity providers.
Team
| Method and path | Description |
|---|---|
GET, POST /api/api-keys |
List keys (prefix, access, expiry, last use; never the key) or create one: { "name", "access"?: "read" | "write", "expiresInDays"? }. Signed-in admins only |
DELETE /api/api-keys/:id |
Revoke a key |
GET /api/audit |
The team's audit log (latest 200 entries). Signed-in admins only |
GET /api/onboarding |
The getting-started checklist and its progress |
Service
| Method and path | Description |
|---|---|
GET /api/health |
Liveness: 200 { "ok": true } when the database answers, else 503. No authentication |
GET /api/health?deep=1 |
Also checks that the SMTP server and worker have checked in recently, that the worker's job loop is running, and counts overdue jobs; 503 when a process is missing or stuck, or DEEP_HEALTH_MAX_OVERDUE (default 50) jobs are overdue. For uptime monitors |
GET /api/health/mail |
Outbound mail (verification, password reset): 503 { "ok": false, "reasons": [...] } when a mail job ran out of retries in the last 30 minutes, the oldest waiting one is over 10 minutes overdue, or sends keep failing. Counts only, no addresses |
GET /api/status |
The public status page as JSON: overall state, components with 90-day uptime, job backlog, incidents. No authentication |
GET /api/metrics |
Prometheus metrics of the web process. For the service operator; needs Authorization: Bearer $METRICS_TOKEN |