Bulk audience send with chunking
Send to 10 000+ recipients efficiently. Sendoka's /api/v1/audiences/:id/send handles this natively — internally chunks by serialized byte count (~500 KB target) to stay under Neon's 1 MB statement cap.
Once — set up the audience
curl -X POST https://api.sendoka.com/api/v1/audiences \
-H "Authorization: Bearer $SENDOKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name": "newsletter-2026-04"}'
Response: { "id": "aud_01HN...", ... }.
Ingest contacts
Batch of up to 5 000 per call. Chunk your own side:
const headers = {
Authorization: `Bearer ${process.env.SENDOKA_API_KEY}`,
"Content-Type": "application/json",
};
const all = await readCsv("./subscribers.csv"); // [{email, name}, ...]
for (let i = 0; i < all.length; i += 5000) {
await fetch("https://api.sendoka.com/api/v1/audiences/aud_01HN.../contacts", {
method: "POST",
headers,
body: JSON.stringify({
contacts: all.slice(i, i + 5000).map((c) => ({
email: c.email,
variables: { name: c.name },
})),
}),
});
}
Send — via template
curl -X POST https://api.sendoka.com/api/v1/audiences/aud_01HN.../send \
-H "Authorization: Bearer $SENDOKA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "news@yourdomain.com",
"template": "newsletter",
"subject": "April picks"
}'
Response is immediate — audience send is queued and delivered by the background cron:
{ "audience_id": "aud_01HN...", "queued": 23417, "skipped_suppressed": 112, "status": "queued" }
Watch progress
curl https://api.sendoka.com/api/v1/audiences/aud_01HN.../status \
-H "Authorization: Bearer $SENDOKA_API_KEY"
{
"total": 23417,
"sent": 18200,
"delivered": 17901,
"bounced": 194,
"complained": 3,
"opened": 8412,
"clicked": 1203
}
Why you shouldn't DIY-chunk
Sendoka already:
- Filters suppressed addresses before insert (org + tenant scoped).
- Sizes each insert batch by
Buffer.byteLength(JSON.stringify(row))to stay under the Neon HTTP 1 MB statement cap. - Applies per-key + per-plan rate limits between batches.
- Writes a single idempotency key per audience send so replays are safe.
- Fires
message.sentwebhooks fromafter()so the HTTP request returns immediately.
If you send 10k rows in a loop via /api/v1/emails, you get 10k round-trips, 10k rate-limit checks, 10k webhook fan-outs. Don't.
Limits
- Max 10 000 recipients in a single audience send — split larger lists.
- Max 5 000 contacts per
addContactscall. - Max 10 tags per message.