What is available today
Read this before you plan a scenario. The API is the part we control and can promise. The app in Make is a separate artifact hosted by Make.The API surface: live
The app in Make: invite only
Getting the app
Open Integrations in Senderz
Open the Make card
Accept the invitation
If you would rather not use the app
You can build the same scenarios with Make’s built-in modules, and it is fully supported:- HTTP → Make a request for every action, search and dropdown.
- Webhooks → Custom webhook for instant triggers, with a Senderz webhook endpoint pointed at the Make webhook URL.
Before you connect
You need two values. Both live in Senderz.Create the connection
Copy your Workspace ID
Create an API key
Make. The key is shown once, in a dialog, with a copy
button. Copy it before you close that dialog. Keys start with sk_evt_.Only an owner or admin can create a key.Paste both into Make
Confirm it works
GET /public/me, which returns your workspace
name, slug, plan and status plus the API version. If that call returns
401, one of the two values is wrong.Use a separate key for Make
A workspace can hold several named keys, so give Make its own. Settings → API Tokens lists them with:Instant triggers
Instant triggers are outbound webhooks. Senderz posts to a URL the moment something happens, and Make starts the scenario.How a trigger is wired
Get a webhook URL
https address.Subscribe
POST /public/webhooks with
{ "url": "...", "events": ["contact.created"] }. From the dashboard it is
Settings → Webhooks.The response includes a signingSecret, returned once and never again.Receive
The delivery Make receives
Every delivery is aPOST with this body:
data object differs per event family:
Events you can subscribe to
There are 29 event types. You can also subscribe an endpoint to* to receive all of them without listing each one.
Contacts and lists
Contacts and lists
contact.created, contact.updated, contact.unsubscribed,
list.subscribed, list.unsubscribed.These fire from any source: the dashboard, an import, the API, a form.Message engagement
Message engagement
email.opened, email.clicked, sms.delivered, sms.failed.Opens and clicks come from Senderz tracking. SMS delivery status comes from
the carrier receipt.Orders, checkout and shipping
Orders, checkout and shipping
order.completed, order.refunded, order.fulfilled,
order.partially_fulfilled, order.cancelled, checkout.started,
cart.abandoned, shipment.confirmed, shipment.out_for_delivery,
shipment.delivered.These come from a connected store. With no store connected, nothing fires.Reviews
Reviews
review.request_ready, review.submitted, review.question,
review.answer.These require a connected reviews app.Loyalty
Loyalty
loyalty.points_earned, loyalty.points_expiring, loyalty.tier_changed,
loyalty.redemption, loyalty.referral.These require a connected loyalty app.campaign.sent: subscribable, not emitted
campaign.sent: subscribable, not emitted
campaign.sent is accepted in a subscription and appears in the event list,
but nothing in Senderz emits it today. An endpoint subscribed to it will
never fire. Do not build a scenario on it.To act when a campaign goes out, trigger on the per-recipient engagement
events instead, or poll the message log.Polling triggers
If you would rather poll than receive webhooks, two endpoints are ordered so a polling trigger works.New or updated profiles
-createdAt for newest first, -updatedAt to catch edits as well as
creations. Also accepts email, firstName, lastName. A - prefix means
descending.offset, it wins over page.subscribed, unsubscribed, never_subscribed or cleaned.email or sms, pairs with consent.createdAt you have seen and stop paging when you reach it.
Message delivery status
id, channel, status, failureReason, providerMessageId, createdAt, sentAt, deliveredAt and updatedAt. Use it to follow up on a transactional send, or fetch one by id with GET /public/messages/{id}.
Actions
Every merchant-facing action is keyed by email. The UUID forms stay available for callers that already hold an id.Create, upsert and update a profile
PUT /public/profiles is the one to reach for in a sync scenario. It looks for a profile by email, then by phone, updates it if found, and creates it if not. POST creates and conflicts on a duplicate. PATCH /public/profiles requires the profile to already exist and returns 404 if it does not.
Identity and locale
Identity and locale
email, phone, firstName, lastName, timezone, locale.On PATCH /public/profiles, email is the lookup key and is required.
Send newEmail to change the address.Consent
Consent
emailConsent, smsConsent, pushConsent, whatsappConsent.Each is one of subscribed, unsubscribed, never_subscribed or
cleaned. Only set consent to subscribed when you hold a real opt-in for
that channel. See Consent and compliance.Address and profile attributes
Address and profile attributes
city, country, stateProvince, zip, address1, address2,
dateOfBirth, gender, jobTitle.These are stored as custom properties rather than as their own columns, so
they come back inside customProperties on a read, not at the top level.
Anything you put in customProperties yourself is merged in alongside them.List membership
Lists in Senderz are manually managed, so both member calls work on any list. There is no separate rule for a different kind of list.- Up to 100 profiles per call, counting
emails,email,contactIdsandcontactIdtogether. - An email that does not match an existing profile is created as a new profile and then added.
- Adding returns
{ added, count }and removing returns{ removed, count }, wherecountis the list size afterwards. - Each add fires
list.subscribedand each removal fireslist.unsubscribed, so one Make scenario can feed another. - If none of the identifiers resolve to a profile, the call returns
400rather than doing nothing quietly.
GET /public/lists, which returns id, name, description, members, color, archived, source and timestamps.
Blacklist
POST /public/profiles/blacklist takes email or contactId, and an optional channel of email, sms or both. channel defaults to email, so pass both if you mean both.
DELETE /public/profiles/blacklist reverses it, and restores the consent state the profile had before it was blacklisted rather than guessing a new one.
Send transactional email
contactId.400.templateId.templateId.subject and html.202 with { "messageId": "..." }. That is an accepted-for-sending id, not a delivery confirmation. Poll GET /public/messages/{id} for status.
If the recipient does not exist as a profile yet, one is created.
Send transactional SMS
contactId.templateId.202 with { "messageId": "..." }.
Send a custom event
email, phone or contactId.value.properties on
purpose: an event property describes the occurrence and must never quietly
become a contact field.{ status, enrolled, contactId, created }. enrolled is how many automations the event started, so a 0 there tells you the event landed but no automation was listening.
Searches and dropdowns
These endpoints exist to fill pickers in Make, so you choose a template or a sender by name instead of pasting a UUID. They all return{ value, label } plus a few extra fields.
GET /public/sender-addresses returns only addresses whose domain is verified and whose mailbox is confirmed. If it comes back empty, that is why POST /public/messages/email is returning 400. Fix it under Settings → Domains & senders, described in Sender addresses and names.
GET /public/events returns the 29 system event names marked kind: "system", plus every custom event your workspace has actually recorded. It is the safest way to populate an event picker, because a name that is not in that list has never been seen in your workspace.
Pagination
Every list and dropdown returns the same envelope insidedata:
offset set to the previous next_cursor until has_more is false. That loop works on every endpoint below.
Page sizes are not identical everywhere:
page and offset are accepted, sending offset wins.
limit and let
the scenario run more often rather than pulling everything in a single pass.The universal API call module
For anything without a dedicated module, use the app’s generic API call module or Make’s HTTP module. The connection supplies both auth headers.https://api.senderz.app/api/v1, so a relative path of /public/profiles resolves to https://api.senderz.app/api/v1/public/profiles.
If you are using Make’s HTTP module directly, set both headers yourself:
{ "success": true, "data": ... }, so map from data in Make, not from the root.
Worked examples
Sync new CRM contacts into a Senderz list
Sync new CRM contacts into a Senderz list
- Trigger: your CRM’s own “new record” module.
- Create or update a profile (
PUT /public/profiles) withemail,firstName,lastName. - Add to a list (
POST /public/lists/{id}/members) withemails: ["{{email}}"]. Pick the list id fromGET /public/lists.
emailConsent: "subscribed" in step 2 unless the CRM record
holds a real opt-in. Adding someone to a list is not the same as having
permission to market to them.Send a templated transactional email from another app
Send a templated transactional email from another app
- Trigger: an event in the other app, for example an invoice being issued.
- Send transactional email with
to, afromEmailfromGET /public/sender-addresses, atemplateIdfromGET /public/templates?channel=email, andtemplateFieldsfilled from the trigger. - Optional: store the returned
messageId, then in a later scenario callGET /public/messages/{id}and alert yourself ifstatusis a failure.
GET /public/templates/{id}/merge-fields once while building to see
exactly which keys templateFields must contain.Send a transactional SMS
Send a transactional SMS
- Trigger: an event in another tool, for example a delivery going out.
- Send transactional SMS with
to,bodyand asenderIdfromGET /public/sms-sender-ids. - Add an error handler on
403so a run with too few credits fails loudly rather than skipping the message.
Push opens and clicks into a spreadsheet or warehouse
Push opens and clicks into a spreadsheet or warehouse
- In Make, add a Custom webhook and copy its URL.
- Subscribe it:
POST /public/webhookswith{ "url": "YOUR_MAKE_WEBHOOK_URL", "events": ["email.opened", "email.clicked"] }. - Map
event,data.contactIdanddata.occurredAtinto your destination.
signingSecret from step 2 somewhere safe and verify
X-Sender-Signature if your destination is sensitive.Fire a custom event that starts a Senderz automation
Fire a custom event that starts a Senderz automation
- Trigger: a subscription renewal in your billing tool.
- Send a custom event to
/events/ingestwithevent: "subscription_renewed", the customer’semail, aneventIdtaken from the billing record, andpropertiessuch as the plan name. - In Senderz, build an automation triggered on
subscription_renewed.
enrolled in the response while testing. A 0 means the event
arrived but no automation is listening yet.Mirror an unsubscribe from another platform
Mirror an unsubscribe from another platform
- Trigger: the unsubscribe event in the other platform.
- Update a profile (
PATCH /public/profiles) withemailandemailConsent: "unsubscribed", or Blacklist a profile withchannel: "both"if you want to stop every channel at once.
Troubleshooting
Building your own Make app
If you are writing a custom Make app rather than using ours, the API publishes a machine-readable OpenAPI description you can import:2026-01. New behaviour is added compatibly.

