KoltrixKoltrix docs

Newsletters

Lists, subscribers, segments, broadcasts, double opt-in, embed forms, drip automations. Everything you'd reach for to run a real newsletter — built on the same transactional pipeline so a broadcast bounce suppresses the same address as a transactional one would, and your message.delivered webhook fires for both.

For multi-step automations (welcome series, onboarding nudges) see Sequences. This page covers everything else.

Lists

A list is an audience with a sender identity (from_name, from_address, optional reply_to) and a set of subscribers.

Create a list

curl https://api.koltrix.com/api/v2/lists \
  -H "Authorization: Bearer kx_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekly product updates",
    "description": "What shipped this week at Acme.",
    "from_name": "Acme Team",
    "from_address": "[email protected]",
    "reply_to": "[email protected]"
  }'

Response:

{
  "id": "0b3c...",
  "name": "Weekly product updates",
  "from_name": "Acme Team",
  "from_address": "[email protected]",
  "subscriber_count": 0,
  "created_at": "2026-05-21T12:00:00Z"
}

from_address must match an active address on a verified sending domain. If it isn't, broadcasts on this list will fail at send time — the API enforces the same strict from check as /api/v2/emails.

Required scope: newsletter (or *). Read-only routes also accept read.

List, read, update, delete

# All lists for the account
curl https://api.koltrix.com/api/v2/lists \
  -H "Authorization: Bearer kx_..."
 
# One list
curl https://api.koltrix.com/api/v2/lists/$LIST_ID \
  -H "Authorization: Bearer kx_..."
 
# Update
curl -X PATCH https://api.koltrix.com/api/v2/lists/$LIST_ID \
  -H "Authorization: Bearer kx_..." \
  -d '{ "description": "New description" }'
 
# Delete
curl -X DELETE https://api.koltrix.com/api/v2/lists/$LIST_ID \
  -H "Authorization: Bearer kx_..."

Subscribers

Add a subscriber

curl https://api.koltrix.com/api/v2/lists/$LIST_ID/subscribers \
  -H "Authorization: Bearer kx_..." \
  -H "Content-Type: application/json" \
  -d '{
    "email": "[email protected]",
    "name":  "Ada Lovelace",
    "tags":  ["beta", "vip"]
  }'

If the list requires double opt-in, the new subscriber starts in pending status and gets a confirmation email pointing at our /c/<token> endpoint. They become active after clicking the confirm link, at which point any subscribe-triggered sequences enroll them.

List subscribers

curl "https://api.koltrix.com/api/v2/lists/$LIST_ID/subscribers?status=active&limit=100" \
  -H "Authorization: Bearer kx_..."

Query params: status (pending / active / unsubscribed / bounced / complained), limit, offset.

Subscriber states

StatusMeaning
pendingAwaiting double-opt-in confirmation
activeWill receive broadcasts and sequence steps
unsubscribedOpted out — broadcasts and sequences skip them silently
bouncedHard-bounced — suppressed automatically
complainedSpam-complained at the receiver — suppressed

Unsubscribe / remove

# Mark unsubscribed (cancels any active sequence enrollments)
curl -X POST https://api.koltrix.com/api/v2/lists/$LIST_ID/subscribers/$SUB_ID/unsubscribe \
  -H "Authorization: Bearer kx_..."
 
# Hard delete the row
curl -X DELETE https://api.koltrix.com/api/v2/lists/$LIST_ID/subscribers/$SUB_ID \
  -H "Authorization: Bearer kx_..."

Bulk import (CSV)

curl https://api.koltrix.com/api/v2/lists/$LIST_ID/subscribers/import \
  -H "Authorization: Bearer kx_..." \
  -H "Content-Type: application/json" \
  -d '{
    "csv": "email,name,tags\[email protected],Ada Lovelace,beta;vip\[email protected],Linus,beta"
  }'

Behaviour:

  • Duplicates are upserted by (list_id, email) — re-importing the same CSV doesn't error or create dupes; it refreshes names and tags.
  • Bad rows are skipped and reported in the response summary.
  • Imported subscribers start as active unless the list requires double opt-in, in which case they start as pending and get a confirm email.

The dashboard equivalent lives under Newsletters → list → Import CSV.

Embed signup form

Put a form on your own site that drops subscribers into a Koltrix list with no API key in the browser. Koltrix issues a per-list public token — fetch it in the dashboard at Newsletters → list → Embed, then paste the snippet onto your page:

<form action="https://api.koltrix.com/api/v1/public/lists/PUBLIC_TOKEN/subscribe"
      method="post">
  <label>
    Email
    <input name="email" type="email" required />
  </label>
  <label>
    Name (optional)
    <input name="name" type="text" />
  </label>
 
  <!-- Honeypot: humans won't fill this, bots will. -->
  <input name="_hp" type="text" style="display:none" tabindex="-1" autocomplete="off" />
 
  <button type="submit">Subscribe</button>
</form>

The endpoint accepts both application/x-www-form-urlencoded (vanilla HTML) and application/json (your own JS), so the same URL works either way. If you pass ?redirect=https://yoursite.com/thanks we 303-redirect on success, which keeps no-JS submissions feeling polished.

Concerned the token has leaked? Rotate it under the same Embed tab. The old token starts failing immediately; you swap the snippet on your site.

Double opt-in

A list with require_double_opt_in = true:

  1. Adding [email protected] creates a subscriber row with status pending.
  2. Koltrix sends a confirmation email containing a one-time confirm URL.
  3. Ada clicks the link → row flips to active and any subscribe-triggered sequences enroll her.

Use double opt-in for any list reachable through a public form. It's the single biggest deliverability lever and the only reliable way to keep spam sign-ups from poisoning your sender reputation.

Broadcasts

A broadcast is a one-shot campaign sent to every active subscriber on a list. Compose in Newsletters → Campaigns → New in the dashboard, or kick one off via the API:

curl https://api.koltrix.com/api/v2/lists/$LIST_ID/broadcast \
  -H "Authorization: Bearer kx_..." \
  -H "Content-Type: application/json" \
  -d '{
    "subject":      "May product update",
    "body_html":    "<h1>Hello!</h1><p>What shipped this month.</p>",
    "body_text":    "Hello!\n\nWhat shipped this month.",
    "preheader":    "Inbox cleanup, faster search, new sequences UI.",
    "from_name":    "Acme Team",
    "from_address": "[email protected]"
  }'

from_name / from_address are optional — they default to whatever the list itself has configured. The response:

{
  "campaign_id": "5a7b...",
  "status": "queued",
  "message": "Broadcast enqueued — recipients will be fanned out by the worker."
}

What the worker does:

  1. Loads active subscribers (skipping unsubscribed, bounced, pending, complained).
  2. Checks the warmup budget for today's sender domain; refuses to start if exceeded.
  3. For each recipient:
    • Adds a unique unsubscribe_token link in the body and a matching List-Unsubscribe header.
    • Injects the tracking pixel and rewrites links (unless the campaign opts out).
    • Sends, writes the outbound row, fires message.sent / message.bounced accordingly.

Templates

Reusable HTML emails. Store them once under Settings → Templates, reference them from a campaign or a transactional send. Placeholders that work everywhere:

  • {{name}} — subscriber name (or empty if not set)
  • {{email}} — recipient email
  • {{unsubscribe_url}} — personalised one-click link, also added as the List-Unsubscribe header

Suppression

The global suppression list is the safety net. An address ends up here automatically when:

  • The recipient hard-bounces (SMTP 5xx).
  • The recipient hits the unsubscribe link.
  • The receiver flags the message as spam and forwards a complaint to our abuse mailbox.

Once on the list, that address is silently skipped on every subsequent send — transactional and newsletter alike — until you remove it under Settings → Suppressions. Removing is one click, but check the recorded reason first; bouncing the same address twice just puts them straight back on the list.

  • Automate a multi-step welcome series → Sequences
  • Trigger broadcasts from cron / Zapier → Integrations
  • Subscribe to per-message delivery events → Webhooks