Reference
On this page
Team & account API
Endpoints for organising and administering a team: projects, API keys, webhooks, the audit log, API mocks, failure scenarios, your own email preferences and the service status. Authentication, roles, errors and paging are described in the API overview.
Projects and systems
A project groups the systems of one app or environment: email inboxes, SMS inboxes, request bins, API mocks, WhatsApp sandboxes and push inboxes. Mock identity providers belong to the whole team.
| Method and path | Role | Description |
|---|---|---|
GET /api/projects |
Member | { projects, ungrouped }: each project with systems (a count per system type) and total, plus the counts of systems in no project |
POST /api/projects |
Admin | Create a project: { "name" } (1 to 80 characters). 201 { project } |
PATCH /api/projects/:id |
Admin | Rename it: { "name" } |
DELETE /api/projects/:id |
Admin | Delete the project. Its systems are kept and become ungrouped. 204 |
GET /api/projects/:id/systems |
Member | Every system in the project, with its type and the API path that moves it. Use ungrouped as the id for systems in no project. No credentials |
{
"projects": [
{
"id": "cm5f1…",
"name": "Checkout · staging",
"createdAt": "2026-10-01T09:00:00.000Z",
"inboxCount": 2,
"systems": { "inboxes": 2, "smsInboxes": 1, "requestBins": 1, "apiMocks": 3, "whatsappSandboxes": 0, "pushInboxes": 0 },
"total": 7
}
],
"ungrouped": { "inboxes": 1, "smsInboxes": 0, "requestBins": 0, "apiMocks": 0, "whatsappSandboxes": 0, "pushInboxes": 0 }
}To move a system into a project, PATCH it with { "projectId": "<id>" } (or null to ungroup it) on its own endpoint, for example PATCH /api/inboxes/:id. Each entry of GET /api/projects/:id/systems names that endpoint in patch.
API keys
API keys are managed by signed-in owners and admins only; API keys get 403.
| Method and path | Role | Description |
|---|---|---|
GET /api/api-keys |
Signed-in admin | { keys }: id, name, prefix (the first 10 characters), access, expiresAt, createdAt, lastUsedAt. Never the key |
POST /api/api-keys |
Signed-in admin | { "name", "access"?: "read" | "write", "expiresInDays"? } (1 to 3650). 201 with the key, shown only in this response |
DELETE /api/api-keys/:id |
Signed-in admin | Revoke a key. It stops working at once. 204 |
Creating more keys than the plan allows answers 402.
Webhooks
Testlie's own event notifications: a signed POST to your URL when mail, a text, a call, a WhatsApp message or a push notification arrives. Included from the Team plan. Payloads, signatures and retries are described in Webhooks.
| Method and path | Role | Description |
|---|---|---|
GET /api/webhooks |
Member | { webhooks }. ?inboxId=<id> lists one inbox's webhooks; ?inboxId=team the team-wide ones. The signing secret is shown to admins only |
POST /api/webhooks |
Admin | Create one: { "url", "inboxId"?, "events"?, "enabled"?, "format"? }. 201 { webhook } with the secret |
PATCH /api/webhooks/:id |
Admin | Change url, inboxId, events, enabled or format; { "rotateSecret": true } replaces the signing secret |
DELETE /api/webhooks/:id |
Admin | Delete the webhook and its delivery log. 204 |
POST /api/webhooks/:id/test |
Admin | Send a signed webhook.test event now (one attempt). { result: { ok, status, error, attempts }, webhook } |
GET /api/webhooks/:id/deliveries |
Member | Delivery log, newest first: limit (default 50, max 200). Kept 30 days |
POST /api/webhooks/:id/deliveries/:deliveryId |
Admin | Redeliver an earlier event with the same payload and a new signature. 202 { delivery } |
| Field | Notes |
|---|---|
url |
http or https, no credentials in the URL. Targets that resolve to private, loopback or link-local addresses are refused |
inboxId |
Only this email inbox. Leave it out (or null) for a team-wide webhook |
events |
The events to send. An empty list [] means all events, including ones added later. Default ["message.received"] |
enabled |
Default true |
format |
json (default, signed JSON), slack (a https://hooks.slack.com/... URL) or teams (an https URL on *.webhook.office.com, *.logic.azure.com or *.powerplatform.com) |
curl -X POST https://app.testlie.com/api/webhooks \
-H "Authorization: Bearer $TESTLIE_API_KEY" -H "Content-Type: application/json" \
-d '{ "url": "https://ci.example.com/hooks/testlie", "events": ["sms.received", "call.completed"] }'{
"webhook": {
"id": "cm6a3…",
"inboxId": null,
"url": "https://ci.example.com/hooks/testlie",
"format": "json",
"events": ["sms.received", "call.completed"],
"enabled": true,
"lastStatus": null,
"lastError": null,
"lastDeliveredAt": null,
"createdAt": "2026-10-23T10:30:00.000Z",
"secret": "whsec_…"
}
}On a plan without webhooks, creating one answers 402 with "code": "feature_unavailable".
Team data
Export everything the team holds, or delete the team. See also the privacy policy.
| Method and path | Who | Description |
|---|---|---|
POST /api/team/exports |
Admin or read-write key | Request a full export of the team's data (202 { "export" }): a zip with JSON per kind of record, every email as .eml and an mbox per inbox; secrets are redacted. Built in the background; owners and admins get an email with the link. One per team per hour (429 with Retry-After). Admins or a read-write key |
GET /api/team/exports |
Admin or any key | The latest exports with status (queued, running, ready, failed), size, expiresAt and, when ready, downloadUrl. Admins or any key |
GET /api/team/exports/:id/download |
Signed-in owner or admin | The zip, for 48 hours. Only for a signed-in owner or admin of the team, never an API key |
POST /api/team/delete |
Signed-in owner | Delete the team, with its members: { "name": "<the team's name>" }. Cancels the subscription first (503 if the payment provider cannot be reached, and nothing is deleted), removes everyone's access at once, deletes the data in the background and emails the members. Signed-in owners only |
Audit log
| Method and path | Role | Description |
|---|---|---|
GET /api/audit |
Signed-in admin | The team's latest 200 audit entries, newest first: { entries } with action (for example inbox.created, api_key.revoked, idp.scim_run), target, actorLabel, details and createdAt |
Getting started checklist
| Method and path | Role | Description |
|---|---|---|
GET /api/onboarding |
Member | { steps, done, total }: the getting-started checklist and its progress |
Email preferences
Your own preferences, not the team's. These endpoints need a signed-in session; API keys get 401.
| Method and path | Description |
|---|---|
GET /api/account/email-preferences |
{ productEmails, available }: whether you get product emails (a welcome, setup reminders and trial reminders; never captured mail), and whether Testlie sends them at all |
PATCH /api/account/email-preferences |
{ "productEmails": false } to stop them; true to get them again |
Every product email also has a one-click unsubscribe link.
API mocks
Payment gateways and the other API mocks share these endpoints. Each mock has an id (used below) and a slug, the 14-hexadecimal-character segment of its baseUrl (https://testlie.com/mock/<slug>), which your app calls.
| Method and path | Role | Description |
|---|---|---|
GET /api/mocks/providers |
Member | The providers a mock can be created for, with their category, decline codes and webhook events |
GET /api/mocks |
Member | List mocks: category (payments, banking, identity, messaging, esign, erp, crm, data, analytics, mcp, telecom; business lists esign, erp, data and analytics together), provider. Credentials are shown to admins only |
POST /api/mocks |
Admin | Create a mock: { "name", "provider", "webhookUrl"?, "projectId"?, "acknowledgeTestData"? }. Provider IDs come from GET /api/mocks/providers. Payment, banking, identity, telecom, DocuSign and Adobe Acrobat Sign mocks need "acknowledgeTestData": true, confirming that only test data will be sent. 201 { mock } |
GET /api/mocks/:id |
Member | One mock, with slug, baseUrl, credentials and snippets |
PATCH /api/mocks/:id |
Admin | Change name, webhookUrl, projectId or settings (the scenarios, merged with the stored ones) |
DELETE /api/mocks/:id |
Admin | Delete the mock and everything it captured. 204 |
POST /api/mocks/:id/rotate |
Admin | Replace one credential ({ "credential": "secretKey" }) or all of them ("all", the default). Old values stop working at once |
GET /api/mocks/:id/calls |
Member | Captured API calls, newest first: objectId, page, limit |
DELETE /api/mocks/:id/calls |
Admin | Clear calls, webhooks and stored objects |
GET /api/mocks/:id/calls/:callId |
Member | One call with its request and response headers and bodies |
GET /api/mocks/:id/webhooks |
Member | Webhooks the mock sent to your app, with their delivery state: objectId, event, limit |
POST /api/mocks/:id/webhooks/:deliveryId/replay |
Admin | Send a webhook again, freshly signed |
GET /api/mocks/:id/objects |
Member | Objects the mock keeps (payments, mandates, envelopes, records, captured events, deliveries, ...): kind, limit |
The provider APIs themselves (/mock/<slug>/...) are described in Mock payment gateways, API mocks and the page for each provider. Creating more mocks than the plan allows answers 402.
Failure scenarios
Switch on outage presets across the team or one project. See Failure scenarios.
| Method and path | Role | Description |
|---|---|---|
GET /api/scenarios |
Member | { presets, active }: the presets with their parameters, and the scenarios switched on |
POST /api/scenarios/:presetId/activate |
Admin | { "projectId"?, "params"?, "durationMinutes"? }. durationMinutes is 1 to 10,080 (default 60); null keeps it on until switched off. Replaces an activation of the same preset and scope. 201 { activation, warnings } |
POST /api/scenarios/:presetId/deactivate |
Admin | { "projectId"? }: without it every scope of the preset is switched off; null only the team-wide one |
POST /api/scenarios/all/deactivate |
Admin | Switch every scenario off |
SDK downloads
| Method and path | Role | Description |
|---|---|---|
GET /api/sdks |
Member | { packages, builtAt }: the client packages you can download |
GET /api/sdks/:file |
Member | One package archive. See SDKs & CLI |
Service status
These endpoints take no authentication.
| Method and path | Description |
|---|---|
GET /api/health |
Liveness: 200 { "ok": true } when the service answers, else 503 |
GET /api/status |
The public status page as JSON: overall state, components with 90-day uptime and incidents |