The Brixus365 Email API: A Developer's Quick Start (Authentication, Idempotency, Webhooks) | Brixus365 Blog
Back to Blog
Guides10 min read

The Brixus365 Email API: A Developer's Quick Start (Authentication, Idempotency, Webhooks)

A first-build walkthrough of the Brixus365 transactional email API -- authentication, sending your first email, idempotency keys, error handling, webhooks, and what to watch for in production.

Brixus365 TeamReviewed and edited by the Brixus365 team
On this page · 11

Transactional email is one of those primitives where the difference between a good API and a bad one shows up in 3am incidents. The bad ones fail silently, swallow retries, and leak deliverability problems. The good ones are boring — they accept your request, give you a clean response, and emit events you can audit.

This guide is a developer’s first-build walkthrough of the Brixus365 transactional email API: authentication, sending your first email, idempotency, error handling, webhooks, templates, and what to watch for moving to production. For backend engineers and SaaS founders evaluating or onboarding the API.

Why a Developer-Friendly Transactional Email API Matters

Transactional email is different from marketing email. A marketing email is a campaign — you batch it, schedule it, measure it across a list. A transactional email is a one-off response to a user action — order confirmation, password reset, security alert — and it must be reliable per-message, low-latency, and traceable to the originating event.

A developer-friendly API for this job has a few traits:

  • Predictable authentication. Same header on every request, no token-rotation dance, scoped keys for sandbox and production.
  • One endpoint that does the obvious thing. POST /v1/emails to send. Not five endpoints, not a “campaign builder” mental model imposed on transactional sends.
  • First-class idempotency. A retry must not duplicate a send.
  • Structured errors. A 4xx tells you what to fix; a 5xx tells you whether to retry.
  • Webhooks for everything that matters downstream. Delivered, bounced, complained, opened, clicked.

The rest of this guide walks through each of these on the Brixus365 API specifically.

The Brixus365 API in 60 Seconds

Base URL: https://api.brixus365.com/v1

Authentication: X-API-Key: bx_live_... header on every request

Send an email:

curl https://api.brixus365.com/v1/emails \
  -X POST \
  -H "X-API-Key: bx_live_xxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c1a-orders-12345" \
  -d '{
    "from": "orders@yourdomain.com",
    "to": "customer@example.com",
    "subject": "Your order is confirmed",
    "html": "<p>Hi {{first_name}}, thanks for your order.</p>"
  }'

Response:

{
  "id": "msg_2cP3kQ...",
  "status": "queued",
  "accepted_at": "2026-06-11T09:14:22Z"
}

That’s the whole story. The rest of the API is variations on this: templates, attachments, scheduled sends, batch operations.

Authentication: X-API-Key for Developer API, JWT for Dashboard

Brixus365 has two authenticated contexts — the developer API and the dashboard — and they use different headers on purpose.

  • X-API-Key: bx_live_... — the developer API path. Used for transactional sends, webhooks, template management, contact operations.
  • Authorization: Bearer <JWT> — the dashboard path. Used by the web app and admin tools.

Each header has one job. The dispatch is by header presence, not by sniffing a shared header value. If you accidentally put an API key in Authorization: Bearer, you will get a 401 — the system treats it as a malformed JWT. Likewise for a JWT in X-API-Key. This is intentional: it keeps logs readable and prevents subtle dispatch bugs.

Creating an API key in the dashboard:

  1. Settings -> Developer -> API Keys -> New Key.
  2. Choose scope: sandbox (for development) or live (for production).
  3. Choose permissions: typically email:send is enough for transactional flows. Add template:read if you’ll reference templates.
  4. Copy the key once — it is shown only at creation.

Key prefixes make environment confusion obvious in logs: bx_test_... for sandbox, bx_live_... for production. Reading bx_test_ in production logs is a clear flag.

Rotation. Rotate keys quarterly or whenever a team member leaves. The dashboard supports creating a new key and revoking the old one without downtime: deploy with the new key first, verify, revoke the old.

Sending Your First Email: POST /v1/emails

The minimal request body:

{
  "from": "orders@yourdomain.com",
  "to": "customer@example.com",
  "subject": "Your order is confirmed",
  "html": "<p>Hi {{first_name}}, thanks for your order.</p>",
  "variables": { "first_name": "Aarav" }
}

Required fields: from, to, subject, and either html or text (or both — for proper plain-text fallback).

A more realistic request:

{
  "from": "orders@yourdomain.com",
  "from_name": "YourBrand Orders",
  "to": "customer@example.com",
  "reply_to": "support@yourdomain.com",
  "subject": "Your order #12345 is confirmed",
  "html": "<p>Hi {{first_name}}...</p>",
  "text": "Hi {{first_name}}...",
  "variables": { "first_name": "Aarav", "order_number": "12345" },
  "tags": ["transactional", "orders", "order_confirmation"],
  "headers": { "X-Order-Id": "12345" }
}

The first response:

{
  "id": "msg_2cP3kQ9X7tYz",
  "status": "queued",
  "accepted_at": "2026-06-11T09:14:22Z"
}

status: queued means the message has been accepted into the send queue. status: sent would mean handed off to the upstream relay. The webhook events tell you what happens next.

Required vs Optional Fields

The fields that earn their place:

  • tags. Arbitrary strings for analytics and segmentation. Tag every transactional send with at least its purpose (order_confirmation, password_reset, security_alert). It costs nothing and the per-tag analytics in the dashboard are useful.
  • headers. Custom RFC-822 headers. Useful for threading (References, In-Reply-To), internal IDs (X-Order-Id), or compliance signals. Note that some headers are reserved (To, From, Subject, List-Unsubscribe) — set those via top-level fields, not via the headers object.
  • reply_to. When the sending address is no-reply and you want replies to go elsewhere.
  • scheduled_at. ISO-8601 datetime. Schedules the send for the future. Useful for time-zoned transactional flows or batched (not one-at-a-time) sends.

The difference between From and Reply-To: From is the sender identity (must be on a verified domain). Reply-To is where replies go. Many transactional flows want from: orders@yourdomain.com (recognisable sender) with reply_to: support@yourdomain.com (where humans actually answer).

Idempotency Keys: Why Every Transactional Send Needs One

The classic bug at scale: your order service POSTs to /v1/emails, the request times out at the network layer, the service retries, and the customer gets two order confirmations. Worse, your accounting system thinks one order generated two receipts.

The fix is an idempotency key: a unique identifier per logical operation. Brixus365 reads it from the Idempotency-Key header.

-H "Idempotency-Key: orders-12345-confirmation"

If you POST the same idempotency key twice within the TTL window, the second call returns the same response as the first (same message ID, same accepted_at) and does not re-send the email.

Constructing the key. A natural pattern is {flow}-{entity_id}-{event}:

  • orders-12345-confirmation
  • accounts-67890-welcome
  • passwords-abc-reset-2026-06-11T09:14:22Z

The point is that the key is deterministic from the originating event. If your retry logic constructs the same key, the duplicate is caught.

TTL. The idempotency cache lives for 24 hours by default. After that, the same key with the same payload becomes a new send. This is rarely an issue for transactional flows where retries happen within minutes.

Handling Errors: The Response Envelope and Retry Policy

All Brixus365 API errors return a unified envelope:

{
  "error": {
    "code": "invalid_recipient",
    "message": "The 'to' field is not a valid email address",
    "type": "validation_error",
    "field": "to"
  }
}

type is the error category — useful for routing in your client code. Common types:

  • validation_error (4xx): a field in your request is wrong. Fix and retry.
  • authentication_error (401): your API key is invalid, expired, or missing. Investigate.
  • permission_error (403): your API key is valid but lacks the required permission scope.
  • rate_limit_error (429): you have exceeded your rate limit. Back off and retry.
  • not_found_error (404): the resource referenced does not exist (e.g., template ID, contact ID).
  • internal_error (5xx): a transient or permanent problem on our side. Retry with backoff.

Retry policy for transactional sends:

  • 4xx errors (except 429): do not retry. The request is wrong; retrying will not fix it.
  • 429: retry with exponential backoff. The Retry-After header tells you the minimum wait.
  • 5xx: retry with exponential backoff up to about 5 attempts. Past that, alert and stop.

A reasonable backoff schedule for transactional retries: 1s, 4s, 16s, 60s, 240s. Combined with the idempotency key, retries are safe.

Webhooks: Subscribing to Delivery, Bounce, Complaint, Open, Click

The send response (status: queued) tells you the message was accepted. Webhooks tell you what happened next.

Setting up a webhook destination:

  1. Settings -> Developer -> Webhooks -> New Endpoint.
  2. Provide the URL (must be HTTPS).
  3. Select the events to subscribe to.
  4. Copy the signing secret.

Event types:

  • email.delivered — accepted by the recipient’s mail server.
  • email.bounced — rejected (with hard/soft sub-classification).
  • email.complained — recipient marked as spam.
  • email.opened — recipient opened (subject to Apple MPP caveats).
  • email.clicked — recipient clicked a link.

The payload:

{
  "event": "email.delivered",
  "message_id": "msg_2cP3kQ9X7tYz",
  "occurred_at": "2026-06-11T09:14:48Z",
  "to": "customer@example.com",
  "tags": ["transactional", "orders", "order_confirmation"],
  "metadata": { "X-Order-Id": "12345" }
}

Signature verification. Every webhook request includes an X-Brixus365-Signature header containing an HMAC-SHA256 of the payload, signed with your endpoint’s signing secret. Verify on every request — accepting unsigned or wrongly-signed payloads is how attackers exfiltrate data.

Idempotency on receipt. Webhooks can be delivered more than once (at-least-once semantics). Your handler must be idempotent on (message_id, event). The simplest pattern: store processed events in a small table keyed by that tuple.

Templates and Dynamic Fields: API vs Dashboard

For transactional flows with stable content, store the template in the dashboard once and reference it by ID:

{
  "from": "orders@yourdomain.com",
  "to": "customer@example.com",
  "template_id": "tpl_order_confirmation_v3",
  "variables": {
    "first_name": "Aarav",
    "order_number": "12345",
    "order_total": "1180.00"
  }
}

Why this beats inline HTML:

  • Designers can edit templates without redeploying code.
  • Template versioning is built in (each save is a version; you can roll back).
  • Per-template analytics — see CTR and delivery rate by template.
  • Compliance: a single approved template prevents drift across services.

Inline HTML is still right for one-off or dynamic content (transactional content that varies wildly per send). The two patterns coexist.

Merge tag syntax: {{ variable_name }}. Brixus365 uses a safe subset of Liquid for templates — fully sandboxed, no arbitrary code execution.

From First API Call to Production

A short pre-launch checklist before you flip a transactional flow to production:

  • Verify your sending domain. Add the verification, DKIM, and SPF records. Set DMARC at p=none initially.
  • Set up the suppression list. Brixus365 manages this automatically — every bounce and complaint goes to suppression. Verify suppressed addresses are excluded from future sends.
  • Subscribe to webhooks for delivered, bounced, complained at minimum. Add open and click if you care about engagement signals.
  • Implement idempotency keys on every transactional send.
  • Set up monitoring. Send-success rate, webhook-receive rate, and 429 frequency are the three to alert on.
  • Verify rate limits for your plan. The default for new accounts is 60 requests per second; higher tiers raise this.
  • Move to a live API key for production. Sandbox keys (bx_test_) accept all requests but do not actually send mail — they are for development.

Then ship. Transactional email is one of those rare integration surfaces where you can move fast if the primitives are right.

Key takeaways

  1. Always send an Idempotency-Key on every transactional send. It is the cheapest defence against duplicate emails in a retry storm — and retry storms happen.
  2. Subscribe to webhook events from day one (delivered, bounced, complained). They are the source of truth for downstream automation, not the synchronous response of POST /v1/emails.
  3. Separate sandbox and production API keys, and rotate keys quarterly. A leaked key is a deliverability incident — design key handling like you would database credentials.

FAQ

How do I authenticate requests to the Brixus365 email API?
Pass your key in the X-API-Key header (keys look like bx_live_…). Keep it server-side and load it from an environment variable — never expose it in client-side code.
Is the Brixus365 email API free?
Yes — the Free plan includes 9,000 emails a month with no credit card, enough to build and run a real integration. Pricing only scales as your volume grows.
Is there an SDK, or do I call the REST API directly?
You call the REST API directly — it’s a plain HTTPS endpoint, so any language works with its standard HTTP client (curl, Python’s requests, Node’s fetch, PHP’s Guzzle). There’s no SDK to install or keep updated.
How do I make retries safe?
Send an idempotency key with each request. If a retry reuses the same key, the API returns the original result instead of sending a duplicate — so a network blip never double-sends a receipt.
How do I track delivery, opens, and bounces?
Subscribe to webhooks. Brixus365 posts delivered, opened, clicked, and bounced events to your endpoint as they happen — that event stream is the source of truth, not the synchronous send response.

If you want to start sending, create a free account — 9,000 emails free per month, no credit card. The full API reference is at docs.brixus365.com.

SharePost on XLinkedIn
Try it free

Send smarter emails with Brixus365

Campaigns and transactional API on one engine. 9,000 emails/month free, no credit card.

Start sending free
9,000 emails/month freeNo credit card required
All articles →
Stay in the loop

New guides, straight to your inbox

Field notes on deliverability, list hygiene, and transactional email — roughly once a month, no fluff.

No spam. Unsubscribe with one click. We respect your inbox.