What the API needs.
A from-address on a verified domain, a recipient, and a template or html and text. The full request shape is in the API reference.
Notix has no native app in either catalogue yet, and does not need one for the common case: an HTTP step to the JSON API sends the email, and an HTTP trigger receives Notix's signed delivery events. This page shows both in Pipedream, and the same send from Zapier's Webhooks step.
Store the API key as a Pipedream environment variable and reference it as process.env.NOTIX_API_KEY. Build the idempotency key from the trigger's record id, so a replayed run answers with the original email instead of sending a second one.
// Environment variable NOTIX_API_KEY is set in Pipedream's settings,
// never typed into the step. steps.trigger.event is the trigger's payload.
export default defineComponent({
async run({ steps, $ }) {
const order = steps.trigger.event;
const response = await fetch("https://app.usenotix.dev/api/v1/emails", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.NOTIX_API_KEY}`,
"Content-Type": "application/json",
// Pipedream may re-run a workflow; the key keeps one email per order.
"Idempotency-Key": `order-${order.id}-receipt`,
},
body: JSON.stringify({
from: "receipts@acme.com",
to: order.customer_email,
templateId: "tpl_receipt_v4",
variables: { orderId: String(order.id), total: order.total },
}),
});
const body = await response.json();
if (!response.ok) {
// { error: { code, message } }; 429 carries Retry-After
throw new Error(`Notix ${response.status} ${body.error?.code}: ${body.error?.message}`);
}
$.export("emailId", body.emailId);
return body;
},
});
Method: POST
URL: https://app.usenotix.dev/api/v1/emails
Headers: Authorization: Bearer {{process.env.NOTIX_API_KEY}}
Content-Type: application/json
Idempotency-Key: order-{{steps.trigger.event.id}}-receipt
Body (JSON):
{
"from": "receipts@acme.com",
"to": "{{steps.trigger.event.customer_email}}",
"templateId": "tpl_receipt_v4",
"variables": { "orderId": "{{steps.trigger.event.id}}" }
}
Response: { "emailId": "..." } Errors: { "error": { "code": "...", "message": "..." } }
Action: Webhooks by Zapier → Custom Request
Method: POST
URL: https://app.usenotix.dev/api/v1/emails
Headers: Authorization | Bearer <your API key, stored in the Zap>
Content-Type | application/json
Idempotency-Key | order-{{Order ID}}-receipt
Data (raw JSON):
{
"from": "receipts@acme.com",
"to": "{{Customer Email}}",
"templateId": "tpl_receipt_v4",
"variables": { "orderId": "{{Order ID}}" }
}
There is no Notix app in Zapier's directory; the Custom Request step is
the supported path and uses the same API as everything else on this page.
Every event Notix sends is signed. The step below uses notix-js, which Pipedream installs on import, to check the signature and the five-minute timestamp window before your workflow acts on it.
// Trigger: HTTP / Webhook. Paste the trigger's URL into the Notix
// dashboard as a webhook endpoint and copy the whsec_ secret into
// NOTIX_WEBHOOK_SECRET in Pipedream's environment variables.
//
// The signature covers the exact bytes Notix sent. Configure the HTTP
// trigger to pass the raw body through to the step (Pipedream parses JSON
// by default; a re-serialised body no longer matches the signature).
import { Notix } from "notix-js";
export default defineComponent({
async run({ steps, $ }) {
const rawBody = steps.trigger.event.body; // must be the raw string
const headers = steps.trigger.event.headers; // X-Notix-Signature, X-Notix-Timestamp
const webhooks = new Notix(process.env.NOTIX_API_KEY).webhooks(process.env.NOTIX_WEBHOOK_SECRET);
// Throws on a bad signature or a timestamp older than five minutes.
const event = webhooks.constructEvent(rawBody, { headers });
if (event.type === "email.bounced" && event.data.bounce.type === "Permanent") {
$.export("invalidAddresses", event.data.to);
// next step: mark the address invalid in your CRM, post to Slack, etc.
}
return event;
},
});
| Event | What to do with it |
|---|---|
email.delivered | Mark the order's receipt as delivered in your database or CRM. |
email.bounced | When bounce.type is Permanent, mark the address invalid and stop other systems mailing it. |
email.complained | Record the complaint against the contact and review what was sent. |
email.suppressed | A send was refused because the address is on the suppression list; ask the customer for a new one. |
contact.unsubscribed | Mirror the unsubscribe into your marketing tool so no system sends to them. |
Zapier's Webhooks by Zapier action with the Custom Request option sends the same POST; the Zapier tab above lists every field. Zapier can also receive Notix events with its Catch Raw Hook trigger, but it cannot run the signature check itself, so keep the endpoint URL private and verify the event in a code step or a downstream service.
A from-address on a verified domain, a recipient, and a template or html and text. The full request shape is in the API reference.
With an idempotency key, a replayed run within 24 hours returns the original id. Without one, it sends again. See idempotency keys.
That the event came from Notix and was not altered or replayed. The scheme is on the signature verification page.
Notix inside the platforms you already deploy on: Supabase, Firebase, Vercel, AWS Lambda and WordPress.
ProductOne JSON API for transactional and marketing email: send, batch, schedule, webhooks, typed SDKs.
LearnHMAC-SHA256 over the timestamp and raw body, a five-minute tolerance, replay protection, and the check in four languages.
Use casesProduct notifications from templates, batched when they fan out, with delivery events back through webhooks.
NotixThe quickstart: verify a domain, copy an API key, send the first email.
NotixA free plan with no card, and Pro at $15 a month for 50,000 emails. Only sent volume is metered.
Verify a domain, copy an API key, make one call. The free plan does not ask for a card.