Create a broadcast
Create a broadcast.
https://app.usenotix.dev/api/v1/broadcastsNeeds a full access key. Sending access keys cannot call this. Key permissions lists the extra rules some calls have.
Create a broadcast. A team's first broadcast is created but held for review before it can send, and answers 202. Pass segmentId to send only to the subscribed contacts of the book who match that segment when the send starts; the segment must belong to contactBookId.
Approval
Every API key has an approval policy, set by a team admin. Keys created before policies existed use the default, APPROVE_OVER_N with N = 50. An admin can turn approval off for a key in the dashboard; that key then schedules without approval and reports its policy as null.
| Policy | What a schedule by the key does |
|---|---|
APPROVE_OVER_N (the default, N = 50) | Up to N recipients sends. Above N it answers 409 APPROVAL_REQUIRED with a draft card in approval, and emails a 6-digit code to the key's owner and the team's admins. Show approval.card to the person, ask them for the code, send it to POST /v1/broadcasts/{broadcastId}/approve, then schedule again with approvalId. |
AUTO_UNDER_N | Up to N recipients sends. Above N it answers 403: send it from the dashboard. |
DRAFT_ONLY | Every schedule answers 403. The key only saves drafts. |
A person must approve: the agent never receives the code, and a schedule only uses an approval a person approved (by the code, or by Approve on the broadcast in the dashboard), presented by approvalId, at least 10 seconds after it was created. A key may send at most 20 approved broadcasts in 24 hours, and ask for at most 10 new approvals an hour. An approval is single use, expires after 24 hours and is bound to the broadcast, its content and the recipient count on the card. The send is capped at that count: contacts added afterwards are not reached. A changed broadcast or count answers 409 again with a new card. A create with sendNow or scheduledAt goes through the same check and keeps its draft when it answers 409.
Dry run
Send the header Notix-Dry-Run: true to see what the request would do without doing it. The answer is 200 with dryRun: true: who it would reach, what they would see, what it would cost, a verdict (allowed and every reasons it would be refused for) and the limits it would count against. Nothing is sent, charged, reserved or written, and the call is recorded in the audit log as a dry run. A write route that cannot preview answers 400.
Body parameters
At most 255 characters.
At most 320 characters.
At most 998 characters.
At most 500 characters.
Send only to this segment of the contact book.
At most 64 characters.
Send only to contacts subscribed to this topic. A contact who unsubscribed from everything is never sent to.
At most 64 characters.
At most 2,000,000 characters.
At most 2,000,000 characters.
The most recipients this campaign may reach. Scheduling is refused (422 RECIPIENT_CAP_EXCEEDED) when the audience is larger. Whether or not you set it, a campaign never reaches more recipients than the count it was scheduled with.
Minimum 1.
Timestamp in ISO 8601 format or natural language (e.g., 'tomorrow 9am', 'next monday 10:30')
Minimum 1. Maximum 100000.
Headers
Bearer followed by your API key.
Set to true to preview the request instead of running it. The answer is 200 with dryRun: true: who it would reach, what they would see, what it would cost, whether policy allows it and the limits it counts against. Nothing is sent, charged, reserved or written. A write route that cannot preview answers 400.
Errors
The API key's approval policy refuses this schedule outright: DRAFT_ONLY keys only save drafts, and AUTO_UNDER_N keys may only send campaigns at or under their threshold. Send it from the dashboard.
APPROVAL_REQUIRED: the API key's approval policy needs a person's yes for a campaign this large. Nothing was sent; a POST /v1/campaigns with sendNow or scheduledAt kept its draft. A 6-digit code was emailed to the key's owner and the team's admins (never returned here). Show `approval.card` to the person, ask them for the code, send it to POST /v1/campaigns/{campaignId}/approve with `approvalId`, then schedule again with `approvalId`. A team admin can instead approve in the dashboard. The approval is single use, expires after 24 hours, can be used 10 seconds after it was created at the earliest, and caps the send at `approval.recipients`; a changed campaign or recipient count needs a new one.
Every error has the same shape. See all error codes.
curl -X POST "https://app.usenotix.dev/api/v1/broadcasts" \
-H "Authorization: Bearer $NOTIX_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme",
"from": "Acme <receipts@acme.com>",
"subject": "Your receipt for order 4471",
"contactBookId": "cm1x8f3k20001qz7v5b9d2e4a",
"html": "<p>Thanks for your order.</p>"
}'
import { Notix } from "notix-js";
const notix = new Notix(process.env.NOTIX_API_KEY);
const { data, error } = await notix.broadcasts.create({
name: "October newsletter",
from: "Acme <news@acme.com>",
subject: "What's new at {{company}}",
contactBookId: "cb_123",
html: '<p>Hi {{firstName,fallback=there}}</p><p><a href="{{notix_unsubscribe_url}}">Unsubscribe</a></p>',
});
from notix import Notix
notix = Notix() # reads NOTIX_API_KEY
campaign, _ = notix.campaigns.create({
"name": "October newsletter",
"from": "Acme <news@acme.com>",
"subject": "What's new at {{company}}",
"contactBookId": "cb_123",
"html": '<p>Hi {{firstName,fallback=there}}</p><p><a href="{{notix_unsubscribe_url}}">Unsubscribe</a></p>',
})
use Notix\Notix;
$notix = new Notix(getenv('NOTIX_API_KEY'));
$campaign = $notix->campaigns->create([
'name' => 'October newsletter',
'from' => 'Acme <news@acme.com>',
'subject' => "What's new at {{company}}",
'contactBookId' => 'cb_123',
'html' => '<p>Hi {{firstName,fallback=there}}</p><p><a href="{{notix_unsubscribe_url}}">Unsubscribe</a></p>',
]);
{
"id": "cm1x8f3k20001qz7v5b9d2e4a",
"name": "Acme",
"from": "Acme <receipts@acme.com>",
"subject": "Your receipt for order 4471",
"previewText": "Thanks for your order.",
"contactBookId": "cm1x8f3k20001qz7v5b9d2e4a",
"segmentId": "cm1x8f3k20001qz7v5b9d2e4a",
"html": "<p>Thanks for your order.</p>",
"content": "string",
"status": "string",
"scheduledAt": "2026-10-01T09:00:00Z",
"batchSize": 1,
"batchWindowMinutes": 1,
"total": 1,
"maxRecipients": 1,
"sent": 1,
"delivered": 1,
"opened": 1,
"clicked": 1,
"unsubscribed": 1,
"bounced": 1,
"hardBounced": 1,
"complained": 1,
"replyTo": [
"string"
],
"cc": [
"string"
],
"bcc": [
"string"
],
"createdAt": "2026-10-01T09:00:00Z",
"updatedAt": "2026-10-01T09:00:00Z"
}