External notifications
Register emails that your own system sent to a customer, so staff can see them in Tillor
Last updated on
Does your system send its own emails to customers (newsletter, booking confirmation, reminder)? Then register them in Tillor. Staff see them on the customer, on the invoice and in the Notifications overview, next to the notifications Tillor sends itself.
Tillor sends nothing: you register a message that has already been sent. External notifications always carry the label External with your source name in the app, so they never pass for a Tillor notification.
Access
The user behind the API key needs one of these permissions in the organisation. An administrator grants them in the organisation's user permissions, in the Notifications group (Register external notifications and Manage other external notifications).
| Permission | What you can do |
|---|---|
notifications:external:write | Register notifications and update or delete your own registrations |
notifications:external:manage-others | Also update or delete registrations of other users or integrations |
One user per integration
Ownership is tied to the user of the API key. Use a separate (service) user per integration, so one integration can never change the notifications of another.
Endpoints
All paths are under /api/orgs/:orgId. Exact schemas: OpenAPI, tag notifications.
| Method | Path | Description |
|---|---|---|
| POST | /notifications/external | Register a notification |
| PATCH | /notifications/external/{id} | Update status, timestamps or content |
| DELETE | /notifications/external/{id} | Delete permanently |
| GET | /notifications?source=EXTERNAL | List registered notifications (also filter on externalSource, externalReference, customerId, invoiceId) |
| GET | /notifications/{id} | Fetch one notification |
Notifications that Tillor sent itself cannot be changed or deleted through these endpoints; they return 404.
Register
curl -X POST "https://tillor.eu/api/orgs/org_abc123/notifications/external" \
-H "x-api-key: tkn_xxx" \
-H "Content-Type: application/json" \
-d '{
"externalSource": "mailchimp",
"externalReference": "campaign-42:member-9f3a",
"name": "Boekingsbevestiging",
"customerId": "clx789...",
"channel": "EMAIL",
"status": "SENT",
"sentAt": "2026-09-19T08:15:00Z",
"email": {
"to": "jan@voorbeeld.nl",
"from": "Recreatiepark Het Meer <info@recreatiepark-het-meer.be>",
"subject": "Je boeking is bevestigd",
"htmlBody": "<p>Dag Jan, ...</p>",
"attachments": [{ "filename": "bevestiging.pdf", "contentType": "application/pdf", "size": 48211 }]
}
}'All fields and limits are in OpenAPI. These fields have rules you need to know beforehand:
| Field | Rule |
|---|---|
externalSource | Name of your system in lowercase letters, digits, ., _ or - (e.g. mailchimp). Staff see this name on the notification |
externalReference | Your own ID for this message, unique within externalSource |
name | Short label for staff (e.g. "Booking confirmation"). It can be searched on |
customerId / invoiceId | At least one of the two. Determines where the notification appears. If you only send invoiceId, Tillor also links the customer of that invoice. An unknown ID, or an invoice of a different customer, gives 400 |
status | SENT, FAILED, BOUNCED or COMPLAINED. Without sentAt for SENT, Tillor uses the moment of registration |
sentAt, readAt, clickedAt | ISO 8601 with time zone, e.g. 2026-09-19T08:15:00Z. Other values are refused |
email.attachments | Metadata only (filename, contentType, size). The files themselves are not stored |
Retrying safely
POST is idempotent on externalSource + externalReference. If you send the same combination again (for example after a timeout), you get the existing notification back and nothing is changed. If you want to change something, use PATCH.
No personal data in externalReference or name
externalSource, externalReference and name are stored unencrypted because they are searched on. Use a technical ID, not an email address or name. An externalReference with @ is refused. Recipient, subject, content and attachments are stored encrypted.
Update and delete
With PATCH, send only the fields that change, for example when an email bounces afterwards:
curl -X PATCH "https://tillor.eu/api/orgs/org_abc123/notifications/external/NOTIFICATION_ID" \
-H "x-api-key: tkn_xxx" \
-H "Content-Type: application/json" \
-d '{ "status": "BOUNCED", "errorMessage": "Mailbox bestaat niet" }'DELETE removes the notification permanently, including its content. Also use this to comply with a deletion request (GDPR).
A PATCH that changes nothing does nothing: no change, no event. If you change the content (label, recipient, sender, subject, text, HTML or attachments) or delete a notification, it appears in the activity log of the customer or invoice, with the user who did it. Updates of status, readAt or clickedAt do not appear there, so you can keep syncing opens and clicks.
HTML and privacy
Tillor shows the HTML to staff as the customer received it, but treats it as untrusted content:
- When saving, scripts, forms, iframes, embeds and event attributes (
onclick, ...) are removed. Links open in a new tab - The preview runs in an isolated frame without scripts and without access to the Tillor session
- External images and fonts do not load automatically, so opening a notification does not trigger a tracking pixel. The staff member can load images per notification
So do not count on "opened" tracking in your system firing when a staff member views the notification.
What Tillor does not do with external notifications
- Does not send (again) or automatically retry
- Does not fetch status updates from your mail provider: you keep the status up to date with
PATCH - Does not count them in the lists Failed Notifications, Bounced Notifications and Pending Notifications or in the counters at the top of the notification overview, because Tillor cannot verify your status. They do appear under Recent Communications
Webhooks and SSE
| Event | When |
|---|---|
notification-delivery:updated | On registering and on every PATCH that changes something. Contains the full notification |
notification-delivery:deleted | On DELETE. Contains only id, source, externalSource, externalReference, customerId and invoiceId |
The field source is EXTERNAL for your registrations and INTERNAL for notifications from Tillor. Filter on it if you want to skip your own events. See Webhooks and SSE.