Authentication
All API requests require authentication via an API key. Keys can be created in your workspace settings.
API Key Format
TopMail API keys use a prefix to indicate their type:
| Prefix | Type | Description |
|---|---|---|
| tm_live_ | Live | Production key. Sends real emails and modifies live data. |
| tm_test_ | Sandbox | Test key. All API calls work normally but email sends return mock results. |
Sending Requests
Include your API key in the Authorization header using the Bearer scheme:
curl https://api.topmail.so/api/v1/contacts \-H "Authorization: Bearer tm_live_abc123"
A legacy header is also supported: X-API-Key: tm_live_.... We recommend using the Authorization header for new integrations.
Rate Limiting
API requests are rate limited per API key using a sliding window. Rate limit details are returned in response headers:
| Name | Type | Required | Description |
|---|---|---|---|
| X-RateLimit-Remaining | number | Optional | Number of requests remaining in the current window. |
| X-RateLimit-Reset | ISO 8601 | Optional | Timestamp when the rate limit window resets. |
| Retry-After | number | Optional | Seconds to wait before retrying (only present on 429 responses). |
When you exceed the rate limit, you will receive a 429 Too Many Requests response:
Permissions
API keys have granular permissions per resource. Each resource can be granted read, write, and delete access independently.
| Resource | Available Permissions |
|---|---|
| contacts | read, write, delete |
| lists | read, write, delete |
| campaigns | read, write |
| templates | read, write |
| flows | read, write |
| analytics | read |
| forms | read, write |
| conversions | read, write |
If a key lacks the required permission, the API returns a 403 Forbidden response:
Idempotency Keys
For mutating endpoints (like sending emails), you can include an Idempotency-Key header to prevent duplicate operations from network retries.
curl -X POST https://api.topmail.so/api/v1/email/send \-H "Authorization: Bearer tm_live_abc123" \-H "Content-Type: application/json" \-H "Idempotency-Key: unique-request-id-123" \-d '{"to": "user@example.com", "subject": "Hello", "html": "<p>Hi</p>"}'
If a request with the same idempotency key has already been processed, the API returns the cached response with an X-Idempotency-Status: cached header. If a request with the same key but a different body is sent, you will receive a 409 Conflict response.
Request IDs
Every API response includes an X-Request-Id header. You can also pass your own via the request header to correlate logs. Include this ID when contacting support.