Server API
The Server API lets your back end send data to Sublim: from curl, PHP, Python, Node.js or anything that speaks HTTP. Use it for what the browser tracker can't see, because it happens on your server.
The first resource is transactional emails: order confirmations, password resets, invoices… sent through your own SMTP server or sending service. Once reported, they appear on the Email Marketing page of the app, next to the campaigns synced from your email tools.
POST and DELETE /api/v2/server/emails: fields, responses and how events map to the page.
Ready-to-use code for curl, PHP, Symfony, Laravel, Python and Node.js.
Server API or tracker?
| Tracker | Server API | |
|---|---|---|
| Runs in | The visitor's browser | Your back end |
| Identifies the project by | Public project ID | Secret key sk_… |
| Measures | Pageviews, sessions, events, purchases | Things only your server knows, such as emails sent |
| Endpoint | /api/v2/events | /api/v2/server/… |
Visitor events (pageviews, sign-ups, purchases) still go through the tracker: it ties them to the visit, the source and the device. Don't replay them from your server.
At a glance
| Base URL | https://tracker.sublimanalytics.com |
| Authentication | Authorization: Bearer sk_…, one secret key per project |
| Format | JSON in, JSON out |
| Resources | Emails |
Create a key
- In the app, open your project, then Project settings → API keys.
- Click Create a key and give it a name that says where it is used, such as
Production SMTP. - Copy the key. It starts with
sk_and is shown only once.
The Your own back end (SMTP) setup on the Email Marketing page offers to create one as well.
A key belongs to one project: requests carry no project ID, the key decides where the data goes. You can have up to 10 active keys per project, for example one per server or environment.
Store the key in an environment variable on your server, such as SUBLIM_API_KEY:
SUBLIM_API_KEY=sk_...
Authentication
Send the key in the Authorization header of every request:
curl https://tracker.sublimanalytics.com/api/v2/server/emails \
-H "Authorization: Bearer $SUBLIM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"events":[{"id":"<a1b2c3@mail.example.com>","event":"sent","template":"order-confirmation"}]}'
A missing, unknown or revoked key gets 401 {"error":"invalid_api_key"}.
Keep the key secret
A secret key lets anyone write data into your project. Use it only on your server: never in browser code, a mobile app or a public repository. If a key leaks, revoke it in Project settings → API keys and create a new one. A revoked key stops working within a minute.
Limits
Limits apply per project, all of its keys together.
| Limit | Value |
|---|---|
| Requests per minute | 1,000 |
| Requests per day (UTC day) | 100,000 |
DELETE requests per minute | 60 |
Events per POST | 500 |
IDs per DELETE | 1,000 |
| Request body | 1 MiB |
Every authenticated response tells you where you stand:
| Header | Description |
|---|---|
X-RateLimit-Limit-Minute | Requests allowed per minute. |
X-RateLimit-Remaining-Minute | Requests left in the current minute. |
X-RateLimit-Limit-Day | Requests allowed per day. |
X-RateLimit-Remaining-Day | Requests left today (UTC). |
Past a limit, the API answers 429 with a Retry-After header, in seconds:
{ "error": "rate_limited", "scope": "minute", "retry_after": 12 }
scope is minute or day: the limit that was reached.
Errors
| Status | Body | Meaning |
|---|---|---|
400 | {"error": "invalid_json"} | The body isn't valid JSON. |
400 | {"accepted": 0, "rejected": […]} | No item passed validation. rejected says why, item by item. |
401 | {"error": "invalid_api_key"} | Missing, unknown or revoked key. |
413 | {"error": "payload_too_large"} | The body is over 1 MiB. |
429 | {"error": "rate_limited", …} | A rate limit was reached. Wait retry_after seconds. |
500 | {"error": "insert_failed"} | Storage failed on our side. Retry later. |
A request with some invalid items still keeps the valid ones: see Responses.
Idempotency
Every item carries your own id. The same id with the same event is stored once, however many times you send it. A request that timed out or failed can therefore be retried as is, without counting anything twice.
Best practices
- Never block your own work on Sublim. Report after the email has gone, from a queue or a background job when you have one. Otherwise use a short timeout (about 2 seconds) and catch every error: a Sublim outage must never stop an email from being sent.
- Batch. Group up to 500 events per request instead of one request per email. It is faster and keeps you far from the rate limits.
- Retry
429and5xxwith an exponential backoff (1 s, 2 s, 4 s…), honouringRetry-After. Don't retry other4xx: fix the request instead. - Keep one key per server or environment, so you can revoke one without touching the others.
Privacy
Recipient addresses are hashed (SHA-256 of the lower-cased address) before being stored: Sublim never keeps them in clear and only uses them for counting. Don't put personal data in template or subject. See Privacy & data.