KoltrixKoltrix docs

Integrations

Koltrix is a normal HTTP + SMTP product, so it plugs into anything that talks HTTP, SMTP, or webhooks. This page collects the patterns that come up most often — Stripe receipts, GitHub notifications, Slack alerts, Zapier / Make connectors, and the embed-form pattern for forms on your own site.

Sending from your own backend

Most integrations boil down to "when X happens in my system, send an email through Koltrix." The pattern is always the same: receive a webhook from the source system, then POST /api/v2/emails.

Stripe receipts

Stripe fires checkout.session.completed when a payment succeeds. Your handler:

// /api/webhooks/stripe (Next.js route handler)
import Stripe from "stripe";
 
export async function POST(req: Request) {
  const sig = req.headers.get("stripe-signature")!;
  const raw = await req.text();
  const event = Stripe.webhooks.constructEvent(raw, sig, process.env.STRIPE_WEBHOOK_SECRET!);
 
  if (event.type === "checkout.session.completed") {
    const session = event.data.object as Stripe.Checkout.Session;
    await fetch("https://api.koltrix.com/api/v2/emails", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${process.env.KOLTRIX_KEY!}`,
        "Content-Type": "application/json",
        "Idempotency-Key": session.id, // safe replay key
      },
      body: JSON.stringify({
        from: "[email protected]",
        to: [session.customer_details!.email!],
        subject: `Receipt for order ${session.id.slice(-6)}`,
        body_html: `<p>Thanks for your order — $${(session.amount_total ?? 0) / 100}.</p>`,
        body_text: `Thanks for your order — $${(session.amount_total ?? 0) / 100}.`,
      }),
    });
  }
  return new Response("ok");
}

Using session.id as the Idempotency-Key means Stripe's automatic retries don't double-send the receipt.

GitHub PR notifications

GitHub fires pull_request events. A handler that emails a code owner when a PR is opened against main:

export async function POST(req: Request) {
  const { action, pull_request, repository } = await req.json();
  if (action !== "opened" || pull_request.base.ref !== "main") {
    return new Response("ignored");
  }
 
  await fetch("https://api.koltrix.com/api/v2/emails", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${process.env.KOLTRIX_KEY!}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      from: "[email protected]",
      to: ["[email protected]"],
      subject: `[${repository.full_name}] ${pull_request.title}`,
      body_html: `<p><a href="${pull_request.html_url}">Review #${pull_request.number}</a></p>`,
    }),
  });
  return new Response("ok");
}

Slack alerting on hard bounces

Subscribe to message.bounced and forward to a Slack incoming webhook:

// /api/webhooks/koltrix
import crypto from "node:crypto";
 
export async function POST(req: Request) {
  const raw = await req.text();
  const sig = req.headers.get("x-koltrix-signature")!;
  const expected = "sha256=" + crypto
    .createHmac("sha256", process.env.KOLTRIX_WEBHOOK_SECRET!)
    .update(raw)
    .digest("hex");
  if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig))) {
    return new Response("bad signature", { status: 401 });
  }
 
  const event = JSON.parse(raw);
  if (event.event === "message.bounced") {
    await fetch(process.env.SLACK_WEBHOOK_URL!, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        text: `:warning: Hard bounce to *${event.to}* — ${event.bounce_reason ?? "no reason"}`,
      }),
    });
  }
  return new Response("ok");
}

A single endpoint can fan out to multiple downstreams — Slack on bounces, PagerDuty on message.complained, your CRM on message.opened. Just branch on event.event.

Zapier / Make / n8n

Koltrix doesn't ship a Zapier app yet, but the REST API works as a generic "POST a webhook" target on the producer side, and the outbound webhook system works as a "trigger Zap on event" consumer:

  • Send email from a Zap: use the Zapier Webhooks by Zapier → POST step pointing at https://api.koltrix.com/api/v2/emails. Set the Authorization header to Bearer kx_....
  • Trigger a Zap from a Koltrix event: add a Koltrix webhook endpoint pointing at the Zapier webhook URL. Pick the events you care about; Zapier hands you the JSON to parse.

Make and n8n work the same way — both have generic HTTP request + webhook nodes that fit Koltrix without a custom connector.

Embed signup forms

Put a form on your marketing site that drops subscribers into a Koltrix list with no API key in the browser. See the full snippet (with honeypot) under Newsletters → Embed signup form; the short version:

<form action="https://api.koltrix.com/api/v1/public/lists/PUBLIC_TOKEN/subscribe"
      method="post">
  <input name="email" type="email" required />
  <input name="_hp" type="text" style="display:none" tabindex="-1" autocomplete="off" />
  <button>Subscribe</button>
</form>

PUBLIC_TOKEN comes from Newsletters → list → Embed. The endpoint accepts both form-encoded and JSON payloads — same URL — so a vanilla HTML form works and a fetch from your SPA works.

If you'd rather keep all traffic server-side, post from your own backend with an API key:

// /api/subscribe handler
await fetch(`https://api.koltrix.com/api/v2/lists/${LIST_ID}/subscribers`, {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.KOLTRIX_KEY}` },
  body: JSON.stringify({ email: req.body.email }),
});

Inbound email parsing

Receive emails to addresses on your verified domain at Settings → Domains → <domain> → Inbound and they'll appear in the dashboard inbox automatically. If you'd rather handle them programmatically:

  1. Add a webhook subscribed to email.inbound.
  2. Your handler receives the parsed email shape:
{
  "event": "email.inbound",
  "timestamp": 1716220800,
  "from": "[email protected]",
  "to": ["[email protected]"],
  "subject": "Re: Demo follow-up",
  "body_html": "<p>Yes, that works…</p>",
  "body_text": "Yes, that works…",
  "in_reply_to": "<[email protected]>",
  "thread_id": "01HX9...",
  "attachments": [
    { "filename": "calendar.ics", "size": 1842, "content_type": "text/calendar" }
  ]
}

Attachment bytes aren't in the webhook (we'd blow your endpoint's body limit) — fetch them with GET /api/v2/mail/{id}/attachments/{att_id}/download.

CRM sync

Koltrix ships a lightweight CRM (contacts + tags) so inbox threads show useful context next to the message. Sync from your source of truth (HubSpot, Salesforce, your own DB) via the contacts API:

curl https://api.koltrix.com/api/v2/contacts \
  -H "Authorization: Bearer kx_..." \
  -d '{
    "email":   "[email protected]",
    "name":    "Ada Lovelace",
    "company": "Acme Co",
    "tags":    ["customer", "annual"]
  }'

Requires the contacts scope. A contact appearing here makes inbox threads from that address show their CRM card next to the message in the dashboard.

Language-by-language ergonomics

LanguageRecommendation
Nodefetch (Node 18+) for REST; nodemailer for SMTP
Pythonrequests for REST; smtplib for SMTP
Gonet/http for REST; net/smtp for SMTP
PHPGuzzle for REST; PHPMailer for SMTP
RubyNet::HTTP for REST; Mail gem for SMTP
Rustreqwest for REST; lettre for SMTP

We don't ship official SDKs today — the REST surface is small enough that your own thin wrapper does the job, and we'd rather not maintain six SDKs that lag behind the API. If that changes, it'll be announced in the docs and on the changelog.

Custom integrations

Anything you can't model with the patterns above usually fits in one of two shapes:

  • Push from your system → Koltrix: your code posts to /api/v2/* with an API key. Use idempotency keys to handle retries.
  • Push from Koltrix → your system: subscribe a webhook with the events you care about, verify the signature, do your thing.

If you've built something cool that other Koltrix users would want, send a writeup to [email protected] — we'll feature it here.