KoltrixDocs

Reference · /api/v2

API reference

Every public Koltrix endpoint. Add a kx_ key below and each endpoint's Try it panel sends the request to api.koltrix.com from your browser and shows the response. Nothing is proxied through this docs site.

Kept in this browser tab only (sessionStorage) and sent only to api.koltrix.com. Create one at app.koltrix.com/api-keys.

Try it sends real requests. Koltrix has no test mode: a send really sends. Use a dedicated key with the fewest permissions that work, and revoke it afterwards. The key stays in this tab (sessionStorage), goes only to api.koltrix.com, and never passes through this docs site.

Transactional email

Send one email to one or more recipients. Requires the send scope. Pass an Idempotency-Key header so a retry can never send twice.

Send an email

POST/api/v2/emails

Queues the message and returns 202 with the id of the first recipient's message record (one record is kept per recipient). The From address must be an active address on a verified domain in your workspace. Fields not listed here, such as reply_to or attachments, are ignored. Every recipient, including cc and bcc, is listed in the sent message's To header. A retry with the same Idempotency-Key within 24 hours returns the original response with status 200 and the header Idempotent-Replayed: true.

Parameters

fromstringbodyrequired
[email protected] or Acme <[email protected]>. Must be an active address on a verified domain in this workspace.
toarraybodyrequired
Array of recipient addresses. Must be an array, even for one recipient.
ccarraybody
Array of additional recipients.
bccarraybody
Array of additional recipients. Currently listed in the To header like every other recipient.
subjectstringbodyrequired
Subject line.
body_htmlstringbody
HTML body. Send this, body_text, or both.
body_textstringbody
Plain-text body. Generated from body_html when omitted.
Idempotency-Keystringheader
Any string identifying this logical send; reuse it on retries. Remembered for 24 hours. The Try it panel generates one per run.
curl -X POST "https://api.koltrix.com/api/v2/emails" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
  "from": "[email protected]",
  "to": [
    "[email protected]"
  ],
  "subject": "Your receipt for order 1042",
  "body_html": "<p>Thanks for your order.</p>",
  "body_text": "Thanks for your order."
}'
{
  "id": "6f1c2a9e-3b7d-4e41-9a52-0c8d1f3e7b20",
  "status": "queued",
  "queued": true,
  "tracking_url": "/api/v2/messages/6f1c2a9e-3b7d-4e41-9a52-0c8d1f3e7b20",
  "recipient_count": 1
}

Messages

Your outbound message log: every message sent through the API, the SMTP relay and broadcasts, one record per recipient. Requires the read or send scope.

List messages

GET/api/v2/messages

Newest first. status is one of queued, sent or bounced.

Parameters

statusstringquery
Only messages with this status: queued, sent or bounced.
recipientstringquery
Only messages whose recipient contains this text (case-insensitive).
limitnumberquery
Page size. Default 100, maximum 500.
offsetnumberquery
How many messages to skip.
curl -X GET "https://api.koltrix.com/api/v2/messages?status=sent&recipient=example.com&limit=50&offset=0" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "data": [
    {
      "id": "6f1c2a9e-3b7d-4e41-9a52-0c8d1f3e7b20",
      "tenant_id": "5c4b3a29-1807-4f6e-9d5c-4b3a29180716",
      "message_id": "[email protected]",
      "from": "[email protected]",
      "to": "[email protected]",
      "subject": "Your receipt for order 1042",
      "status": "sent",
      "open_count": 2,
      "click_count": 0,
      "created_at": "2026-10-02T14:00:00Z",
      "sent_at": "2026-10-02T14:00:01Z",
      "opened_at": "2026-10-02T14:07:04Z"
    }
  ],
  "total": 1
}

Get a message

GET/api/v2/messages/:id

One message with its status, engagement counters and timestamps. engagement_score adds 1 per open, 5 per click and 10 per reply. Currently answers 404 while the message is still queued, usually for under a second.

Parameters

idstringpathrequired
The message id returned by POST /api/v2/emails.
curl -X GET "https://api.koltrix.com/api/v2/messages/6f1c2a9e-3b7d-4e41-9a52-0c8d1f3e7b20" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "id": "6f1c2a9e-3b7d-4e41-9a52-0c8d1f3e7b20",
  "from": "[email protected]",
  "to": "[email protected]",
  "subject": "Your receipt for order 1042",
  "status": "sent",
  "open_count": 2,
  "click_count": 0,
  "reply_count": 1,
  "engagement_score": 12,
  "first_open_after_seconds": 423,
  "message_id": "[email protected]",
  "error": null,
  "created_at": "2026-10-02T14:00:00Z",
  "sent_at": "2026-10-02T14:00:01Z",
  "opened_at": "2026-10-02T14:07:04Z",
  "clicked_at": null,
  "replied_at": "2026-10-02T15:12:40Z",
  "bounced_at": null
}

List a message's events

GET/api/v2/messages/:id/events

Every open, click and reply, oldest first. kind is open, click or reply; a click also has the url. prefetch: true marks an open that looks like automatic image fetching by a mail provider; those are not counted in open_count.

Parameters

idstringpathrequired
The message id.
curl -X GET "https://api.koltrix.com/api/v2/messages/6f1c2a9e-3b7d-4e41-9a52-0c8d1f3e7b20/events" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "data": [
    {
      "kind": "open",
      "prefetch": true,
      "ip": "17.58.0.12",
      "user_agent": "Mozilla/5.0",
      "created_at": "2026-10-02T14:00:03Z"
    },
    {
      "kind": "open",
      "prefetch": false,
      "ip": "203.0.113.7",
      "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 14_5)",
      "created_at": "2026-10-02T14:07:04Z"
    },
    {
      "kind": "reply",
      "prefetch": false,
      "user_agent": "inbound-mail",
      "created_at": "2026-10-02T15:12:40Z"
    }
  ],
  "total": 3
}

Your key

Check which workspace an API key belongs to and which scopes it has.

Get the current key

GET/api/v2/me

Returns the workspace short name (tenant) and the key's scopes. Works with any valid key, so it makes a good health check.

curl -X GET "https://api.koltrix.com/api/v2/me" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "tenant": "acme",
  "permissions": [
    "read",
    "send"
  ]
}

Lists

Newsletter audiences, available over the API only for now. Reading needs read or newsletter; changes need newsletter.

List lists

GET/api/v2/lists

Every list in the workspace.

curl -X GET "https://api.koltrix.com/api/v2/lists" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "data": [
    {
      "id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
      "name": "Product updates",
      "description": "What shipped this month",
      "from_name": "Acme",
      "from_address": "[email protected]",
      "reply_to": "",
      "subscriber_count": 1284,
      "created_at": "2026-09-12T09:14:22Z",
      "updated_at": "2026-10-01T08:00:00Z"
    }
  ]
}

Create a list

POST/api/v2/lists

Returns 201 with the new list. from_address is the default sender for broadcasts and sequences on the list; use an active address on a verified domain.

Parameters

namestringbodyrequired
The list's name.
descriptionstringbody
A note for your team.
from_namestringbody
Default sender name.
from_addressstringbody
Default sender address.
reply_tostringbody
Stored with the list.
curl -X POST "https://api.koltrix.com/api/v2/lists" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Product updates",
  "description": "What shipped this month",
  "from_name": "Acme",
  "from_address": "[email protected]"
}'
{
  "id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
  "name": "Product updates",
  "description": "What shipped this month",
  "from_name": "Acme",
  "from_address": "[email protected]",
  "reply_to": "",
  "subscriber_count": 0,
  "created_at": "2026-10-02T10:11:12Z",
  "updated_at": "2026-10-02T10:11:12Z"
}

Get a list

GET/api/v2/lists/:id

One list. 404 if there is no such list.

Parameters

idstringpathrequired
The list id.
curl -X GET "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
  "name": "Product updates",
  "description": "What shipped this month",
  "from_name": "Acme",
  "from_address": "[email protected]",
  "reply_to": "",
  "subscriber_count": 1284,
  "created_at": "2026-09-12T09:14:22Z",
  "updated_at": "2026-10-01T08:00:00Z"
}

Update a list

PATCH/api/v2/lists/:id

Changes only the fields you send and returns the updated list.

Parameters

idstringpathrequired
The list id.
namestringbody
New name.
descriptionstringbody
New description.
from_namestringbody
New default sender name.
from_addressstringbody
New default sender address.
reply_tostringbody
New reply-to value.
curl -X PATCH "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Changelog"
}'
{
  "id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
  "name": "Changelog",
  "description": "What shipped this month",
  "from_name": "Acme",
  "from_address": "[email protected]",
  "reply_to": "",
  "subscriber_count": 1284,
  "created_at": "2026-09-12T09:14:22Z",
  "updated_at": "2026-10-02T10:12:00Z"
}

Delete a list

DELETE/api/v2/lists/:id

Deletes the list and its subscribers. Cannot be undone. Returns 204 with an empty body.

Parameters

idstringpathrequired
The list id.
curl -X DELETE "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d" \
  -H "Authorization: Bearer $KOLTRIX_KEY"

Empty body. A 204 means it worked.

Subscribers

The people on a list. Reading needs read or newsletter; changes need newsletter.

List subscribers

GET/api/v2/lists/:id/subscribers

status is one of pending (waiting for double opt-in), active or unsubscribed.

Parameters

idstringpathrequired
The list id.
statusstringquery
Only subscribers with this status.
limitnumberquery
Page size. Default 100.
offsetnumberquery
How many to skip.
curl -X GET "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d/subscribers?status=active&limit=100&offset=0" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "data": [
    {
      "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
      "list_id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
      "email": "[email protected]",
      "name": "Ada Lovelace",
      "status": "active",
      "unsubscribe_token": "4f9a0c1d2e3b4a5f6c7d8e9f0a1b2c3d",
      "tags": [
        "beta"
      ],
      "created_at": "2026-09-20T14:01:00Z",
      "updated_at": "2026-09-20T14:01:00Z"
    }
  ],
  "total": 1
}

Add a subscriber

POST/api/v2/lists/:id/subscribers

Returns 201 with the subscriber. Adding an email that is already on the list updates its name instead of failing; someone who unsubscribed stays unsubscribed. On a list that requires double opt-in the subscriber starts as pending.

Parameters

idstringpathrequired
The list id.
emailstringbodyrequired
The address. Stored lower-cased.
namestringbody
The person's name, used by the name merge variables in broadcasts.
tagsarraybody
Array of strings.
curl -X POST "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d/subscribers" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "email": "[email protected]",
  "name": "Ada Lovelace",
  "tags": [
    "beta"
  ]
}'
{
  "id": "9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a",
  "list_id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
  "email": "[email protected]",
  "name": "Ada Lovelace",
  "status": "active",
  "unsubscribe_token": "4f9a0c1d2e3b4a5f6c7d8e9f0a1b2c3d",
  "tags": [
    "beta"
  ],
  "created_at": "2026-10-02T10:14:33Z",
  "updated_at": "2026-10-02T10:14:33Z"
}

Import subscribers from CSV

POST/api/v2/lists/:id/subscribers/import

Send the CSV as a string. A header row with email, name (or first_name or full_name) and tags columns is recognised; without one, the first column is the email. Separate tags with semicolons. Every imported row becomes active, even on a list that requires double opt-in, so import only people who agreed to hear from you. Addresses on your suppression list are still never mailed. Rows with an invalid email are skipped.

Parameters

idstringpathrequired
The list id.
csvstringbodyrequired
The CSV file's contents.
curl -X POST "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d/subscribers/import" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "csv": "email,name,tags\[email protected],Ada Lovelace,beta;vip\[email protected],Linus,beta"
}'
{
  "imported": 2,
  "skipped": 0,
  "errors": null
}

Delete a subscriber

DELETE/api/v2/lists/:id/subscribers/:sub_id

Removes the subscriber from the list. To stop mailing someone but keep the record, unsubscribe them instead. Returns 204 with an empty body.

Parameters

idstringpathrequired
The list id.
sub_idstringpathrequired
The subscriber id.
curl -X DELETE "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d/subscribers/9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a" \
  -H "Authorization: Bearer $KOLTRIX_KEY"

Empty body. A 204 means it worked.

Unsubscribe a subscriber

POST/api/v2/lists/:id/subscribers/:sub_id/unsubscribe

Marks the subscriber unsubscribed, stops any sequence they are in and adds the address to your suppression list, exactly as if they had clicked the unsubscribe link. No body.

Parameters

idstringpathrequired
The list id.
sub_idstringpathrequired
The subscriber id.
curl -X POST "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d/subscribers/9d8c7b6a-5f4e-4d3c-b2a1-0f9e8d7c6b5a/unsubscribe" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "status": "unsubscribed"
}

Broadcasts

Send one message to every active subscriber on a list. Requires the newsletter scope.

Send a broadcast

POST/api/v2/lists/:id/broadcast

Creates a campaign and queues it straight away; returns 202. Each subscriber gets their own copy with an unsubscribe link and header, open tracking and tracked links. In the body, the merge variables {{name}}, {{first_name}}, {{first_name|fallback}}, {{email}} and {{unsubscribe_url}} are filled in per recipient (the subject is sent as written). from_address and from_name default to the list's.

Parameters

idstringpathrequired
The list id.
subjectstringbodyrequired
Subject line.
body_htmlstringbodyrequired
HTML body.
body_textstringbody
Plain-text body. Generated from the HTML when omitted.
preheaderstringbody
Preview text shown after the subject in most inboxes.
from_namestringbody
Sender name. Defaults to the list's.
from_addressstringbody
Sender address. Defaults to the list's; required if the list has none.
curl -X POST "https://api.koltrix.com/api/v2/lists/0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d/broadcast" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "subject": "What shipped in October",
  "body_html": "<p>Hi {{first_name|there}},</p><p>This month we shipped…</p>",
  "body_text": "Hi {{first_name|there}}, this month we shipped…",
  "preheader": "Faster search and a new inbox"
}'
{
  "campaign_id": "1d2c3b4a-5f6e-4d7c-8b9a-0f1e2d3c4b5a",
  "status": "queued",
  "message": "Broadcast enqueued — recipients will be fanned out by the worker."
}

Sequences

Timed series of emails sent to people who join a list. Reading needs read or newsletter; changes need newsletter.

List sequences

GET/api/v2/sequences

Every sequence in the workspace, with its number of steps.

curl -X GET "https://api.koltrix.com/api/v2/sequences" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "data": [
    {
      "id": "3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
      "list_id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
      "name": "Welcome series",
      "trigger": "subscribe",
      "active": true,
      "step_count": 3,
      "created_at": "2026-09-21T12:00:00Z",
      "updated_at": "2026-09-21T12:00:00Z"
    }
  ]
}

Create a sequence

POST/api/v2/sequences

Returns 201. trigger defaults to subscribe, the only trigger: people are enrolled when they become active on the list.

Parameters

namestringbodyrequired
The sequence's name.
list_idstringbodyrequired
The list whose new subscribers are enrolled.
triggerstringbody
subscribe (the default and only value).
curl -X POST "https://api.koltrix.com/api/v2/sequences" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Welcome series",
  "list_id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
  "trigger": "subscribe"
}'
{
  "id": "3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
  "list_id": "0b3c6d2e-91f4-4a7b-8c5d-2e3f4a5b6c7d",
  "name": "Welcome series",
  "trigger": "subscribe",
  "active": true,
  "step_count": 0,
  "created_at": "2026-10-02T12:00:00Z",
  "updated_at": "2026-10-02T12:00:00Z"
}

Delete a sequence

DELETE/api/v2/sequences/:id

Deletes the sequence and its steps. Returns 204 with an empty body.

Parameters

idstringpathrequired
The sequence id.
curl -X DELETE "https://api.koltrix.com/api/v2/sequences/3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9" \
  -H "Authorization: Bearer $KOLTRIX_KEY"

Empty body. A 204 means it worked.

List a sequence's steps

GET/api/v2/sequences/:id/steps

The steps in order of position.

Parameters

idstringpathrequired
The sequence id.
curl -X GET "https://api.koltrix.com/api/v2/sequences/3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9/steps" \
  -H "Authorization: Bearer $KOLTRIX_KEY"
{
  "data": [
    {
      "id": "7e6d5c4b-3a29-4f18-8e7d-6c5b4a392817",
      "sequence_id": "3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
      "position": 0,
      "delay_hours": 0,
      "subject": "Welcome to Acme",
      "body_html": "<p>Hi {{first_name|there}}, glad you're here.</p>",
      "body_text": "Hi {{first_name|there}}, glad you're here.",
      "created_at": "2026-10-02T12:01:00Z"
    }
  ]
}

Add a step

POST/api/v2/sequences/:id/steps

Returns 201. delay_hours is counted from the previous step (from enrolment for the first step). In step bodies {{email}} and {{unsubscribe_url}} are filled in; the name variables are always empty, so give {{first_name}} a fallback.

Parameters

idstringpathrequired
The sequence id.
positionnumberbodyrequired
Order in the sequence, starting at 0.
delay_hoursnumberbodyrequired
Hours to wait after the previous step.
subjectstringbodyrequired
Subject line.
body_htmlstringbody
HTML body.
body_textstringbody
Plain-text body.
curl -X POST "https://api.koltrix.com/api/v2/sequences/3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9/steps" \
  -H "Authorization: Bearer $KOLTRIX_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "position": 0,
  "delay_hours": 0,
  "subject": "Welcome to Acme",
  "body_html": "<p>Hi {{first_name|there}}, glad you'\''re here.</p>",
  "body_text": "Hi {{first_name|there}}, glad you'\''re here."
}'
{
  "id": "7e6d5c4b-3a29-4f18-8e7d-6c5b4a392817",
  "sequence_id": "3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9",
  "position": 0,
  "delay_hours": 0,
  "subject": "Welcome to Acme",
  "body_html": "<p>Hi {{first_name|there}}, glad you're here.</p>",
  "body_text": "Hi {{first_name|there}}, glad you're here.",
  "created_at": "2026-10-02T12:01:00Z"
}

Delete a step

DELETE/api/v2/sequences/:id/steps/:step_id

Returns 204 with an empty body.

Parameters

idstringpathrequired
The sequence id.
step_idstringpathrequired
The step id.
curl -X DELETE "https://api.koltrix.com/api/v2/sequences/3a2b1c0d-9e8f-4a7b-b6c5-d4e3f2a1b0c9/steps/7e6d5c4b-3a29-4f18-8e7d-6c5b4a392817" \
  -H "Authorization: Bearer $KOLTRIX_KEY"

Empty body. A 204 means it worked.