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:

bash
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:

json
{ "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