API & Automation

Programmatically search messages, extract activation links in automated tests, manage projects, and configure granular API key permissions.

Sinkbox provides a full REST API designed specifically for CI/CD test automation, end-to-end testing frameworks (such as Playwright, Cypress, Pest, and Jest), and programmatic project management.

Automated Testing Quickstart

Trigger an email or SMS from your application during a test run, then query Sinkbox to instantly receive the message, extract links, and assert against the contents without polling third-party mailboxes.

Authentication

Sinkbox supports four flexible authentication methods to fit different test runners and HTTP clients:

Method Header / Format Example
Bearer Token Authorization: Bearer <API_KEY> Authorization: Bearer sk_live_...
Basic Auth Authorization: Basic base64(<USER>:<KEY>) -u username:key
X-API-Key Header X-API-Key: <API_KEY> X-API-Key: sk_live_...
URL Credentials /api/{username}/{key}/v1/... /api/user123/keyabc/v1/messages/latest

Granular API Key Permissions

Every API key in Sinkbox can be restricted to specific ingestion channels and API capabilities. This ensures test runners, CI bots, and external tools only have the exact access they need.

Ingestion Service Permissions

Control which channels and drop-in endpoints the key can ingest into:

  • smtp — SMTP inbound gateway
  • resend, sendgrid — Email drop-ins
  • twilio_sms, twilio_voice, twilio_whatsapp
  • 46elks_sms, 46elks_voice
  • fcm, apns, onesignal — Push notifications
  • slack, teams, discord — Webhooks
  • sentry — Error report envelopes
  • email, sms, dump — Direct JSON API ingest

Action & Management Permissions

Control API access to stored items and project resources:

  • messages:read — Read messages, inspect links, and query the latest message.
  • projects:read — List organization projects and check project status.
  • projects:create — Create new projects programmatically within plan quotas.
  • items:delete[Destructive] Delete single messages or purge project inboxes.
  • projects:delete[Destructive] Delete projects permanently.

Security Note

Destructive actions (items:delete and projects:delete) are excluded from default permissions and must be enabled explicitly when creating an API key. Administrative functions (such as member management, billing, and key reveals) are strictly prohibited via API keys and only accessible via authenticated web sessions.

Message Testing & Link Extraction Endpoints

1. Fetch the Latest Message

Retrieves the single newest message in the project matching your filter criteria. Perfect for fetching verification codes, activation emails, or password reset tokens in automated test flows.

GET
GET https://ingest.sinkbox.dev/api/v1/messages/latest?to=user@example.com
Authorization: Bearer <API_KEY>

Available query parameters:

  • to / receiver — Filter by recipient email or phone number.
  • from / sender — Filter by sender email or phone number.
  • subject — Filter by subject text match.
  • type — Filter by message type (email, sms, push, dump, sentry).
  • unread=true — Limit to unread messages.
  • tag — Filter by tag.

Example Response:

json
{
  "id": "msg_9f83a0bc81d",
  "type": "email",
  "sender": "no-reply@myapp.com",
  "receiver": "tester@example.com",
  "subject": "Confirm your registration",
  "content": "Welcome! Please verify your account at https://myapp.com/verify?token=abc123xyz",
  "html_content": "<p>Welcome! Click <a href=\"https://myapp.com/verify?token=abc123xyz\">here</a> to verify.</p>",
  "links": [
    "https://myapp.com/verify?token=abc123xyz"
  ],
  "activation_link": "https://myapp.com/verify?token=abc123xyz",
  "tags": ["auth"],
  "is_read": false,
  "is_pinned": false,
  "size_bytes": 1024,
  "attachments": [],
  "created_at": "2026-09-08T15:30:00+00:00"
}

2. Extract Message Links

Extracts all URLs found in both the HTML and plain-text message bodies and automatically determines the primary activation URL (matching verify, activate, confirm, token, register, magic link patterns).

GET
GET https://ingest.sinkbox.dev/api/v1/messages/{id}/links
Authorization: Bearer <API_KEY>

3. Get Raw & HTML Message Content

Fetch raw MIME / textual payloads or rendered HTML directly:

GET
GET https://ingest.sinkbox.dev/api/v1/messages/{id}/raw
GET https://ingest.sinkbox.dev/api/v1/messages/{id}/html
GET https://ingest.sinkbox.dev/api/v1/messages/{id}/attachments/{attachmentId}
Authorization: Bearer <API_KEY>

4. List & Search Messages

GET
GET https://ingest.sinkbox.dev/api/v1/messages?to=user@example.com&page=1
Authorization: Bearer <API_KEY>

Outbound Webhooks

On Business and Custom plans, Sinkbox can automatically dispatch HTTP POST webhooks to your application whenever new messages arrive.

Webhook Security & Signatures:

Each webhook payload is signed with an HMAC-SHA256 signature using your webhook endpoint secret. The signature is sent in the header:

http
X-Sinkbox-Signature: sha256=<hmac_hash>
X-Sinkbox-Event: message.created
X-Sinkbox-Delivery: <uuid>

Webhook Payload Format:

json
{
  "event": "message.created",
  "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "created_at": "2026-09-08T22:30:00Z",
  "data": {
    "id": "msg_89f1a0b3e1",
    "project_slug": "my-project",
    "type": "email",
    "sender": "noreply@auth.com",
    "receiver": "user@example.com",
    "subject": "Your Login OTP",
    "tags": ["otp"],
    "size_bytes": 1024,
    "has_attachments": false,
    "received_at": "2026-09-08T22:30:00Z"
  },
  "links": {
    "message": "https://ingest.sinkbox.dev/api/v1/messages/msg_89f1a0b3e1",
    "raw": "https://ingest.sinkbox.dev/api/v1/messages/msg_89f1a0b3e1/raw",
    "html": "https://ingest.sinkbox.dev/api/v1/messages/msg_89f1a0b3e1/html"
  }
}

Project & Lifecycle Management Endpoints

1. List Projects

List all projects in the API key's organisation.

GET
GET https://ingest.sinkbox.dev/api/v1/projects
Authorization: Bearer <API_KEY>

2. Create a Project

Creates a new project dynamically within your plan allowance and generates a default API key.

POST
POST https://ingest.sinkbox.dev/api/v1/projects
Authorization: Bearer <API_KEY>
Content-Type: application/json

{
  "name": "E2E Test Run #412"
}

3. Delete a Project

DELETE
DELETE https://ingest.sinkbox.dev/api/v1/projects/{slug}
Authorization: Bearer <API_KEY>

4. Purge Inbox Messages

Purges all messages (or filtered messages) from the project inbox to ensure a clean state between test suites.

DELETE
DELETE https://ingest.sinkbox.dev/api/v1/messages
Authorization: Bearer <API_KEY>

Code Examples

Playwright / JavaScript:

tests/e2e/auth.spec.ts javascript
import { test, expect } from '@playwright/test';

test('user registration and email confirmation', async ({ page, request }) => {
  const email = `test-${Date.now()}@example.com`;

  // 1. Submit signup form in the app
  await page.goto('https://myapp.com/register');
  await page.fill('input[name="email"]', email);
  await page.click('button[type="submit"]');

  // 2. Query Sinkbox API for the latest activation link
  const response = await request.get('https://ingest.sinkbox.dev/api/v1/messages/latest', {
    params: { to: email },
    headers: { Authorization: `Bearer ${process.env.SINKBOX_API_KEY}` }
  });

  expect(response.ok()).toBeTruthy();
  const message = await response.json();
  expect(message.activation_link).toBeDefined();

  // 3. Visit the confirmation link in the browser
  await page.goto(message.activation_link);
  await expect(page.locator('h1')).toContainText('Email Verified');
});

Pest / PHP:

tests/Feature/AuthTest.php php
use Illuminate\Support\Facades\Http;

test('sends verification email with valid activation link', function () {
    $email = 'tester@example.com';

    // 1. Trigger application action
    $this->post('/register', ['email' => $email]);

    // 2. Fetch the latest email from Sinkbox
    $response = Http::withToken(config('services.sinkbox.key'))
        ->get('https://ingest.sinkbox.dev/api/v1/messages/latest', [
            'to' => $email,
        ]);

    expect($response->successful())->toBeTrue();
    $activationLink = $response->json('activation_link');

    expect($activationLink)->not->toBeNull()
        ->and($activationLink)->toContain('/verify?token=');
});