Skip to main content
Overview Use the HTTP examples or a minimal client to call the API. Lightweight clients keep surface area small while providing ergonomics. JavaScript SDK (@fluxomail/sdk)
npm i @fluxomail/sdk
Send with CC/BCC and attachments (Node):
import { Fluxomail } from '@fluxomail/sdk'
import { readFile } from 'node:fs/promises'

const fm = new Fluxomail({ apiKey: process.env.FLUXOMAIL_API_KEY })

await fm.sends.send({
  to: 'user@example.com',
  subject: 'Hello',
  content: 'Hi there',
  htmlContent: '<p>Hi there</p>',
  cc: ['c1@example.com'],
  bcc: 'b1@example.com',
  attachments: [
    {
      filename: 'report.pdf',
      content: await readFile('report.pdf'), // Buffer | Uint8Array | string | Blob (browser)
      contentType: 'application/pdf'
    }
  ],
  idempotencyKey: 'send-123'
})
Notes:
  • Use apiKey server-side only. In browsers, mint short‑lived tokens on your server.
  • The SDK maps content/htmlContent to the public API and encodes attachments to base64 (supports Blob/File in browsers).
Response metadata
const { data, meta } = await fm.events.listWithMeta({ limit: 1 })
console.log(meta.requestId)
Retry policy
const fm = new Fluxomail({ apiKey, retry: { maxAttempts: 5, retriableStatuses: [408, 429], baseDelayMs: 200, maxDelayMs: 1500 } })
Per-request overrides (reads)
// Override timeout and retry only for this call
await fm.events.list({ limit: 1, timeoutMs: 2000, retry: { maxAttempts: 5, baseDelayMs: 100 } })
Browser (token + SSE):
import { Fluxomail } from '@fluxomail/sdk'

// Get a short-lived token from your server (Next.js example route: /api/fluxomail/token)
const { token } = await fetch('/api/fluxomail/token', { method: 'POST' }).then(r => r.json())

const fm = new Fluxomail({ token, getToken: async () => {
  // Auto-refresh tokens for REST calls after a 401
  const r = await fetch('/api/fluxomail/token', { method: 'POST' })
  return (await r.json()).token
}})

// Subscribe to realtime events, persisting a checkpoint
const sub = fm.events.subscribe({ types: ['email.*'], checkpoint: {
  get: () => localStorage.getItem('fluxo:lastEventId') || undefined,
  set: (id) => localStorage.setItem('fluxo:lastEventId', id)
}}, (evt) => {
  console.log('event', evt)
})

// Later: sub.close()
Iterate timelines & abort requests:
// Iterate a send's timeline (auto-paging)
for await (const evt of fm.timelines.iterate({ sendId: 'send_abc123', limit: 100 })) {
  console.log('timeline', evt)
}

// Abort a long-running list
const ac = new AbortController()
const p = fm.events.list({ types: ['email.*'], limit: 1000, signal: ac.signal })
ac.abort()
TypeScript (fetch)
export type SendParams = {
  baseUrl?: string;
  apiKey: string;
  to: string; subject: string; content: string; htmlContent?: string;
  idempotencyKey?: string; policyKey?: string;
};

export async function sendEmail(p: SendParams) {
  const base = p.baseUrl || 'https://api.fluxomail.com';
  const res = await fetch(`${base}/api/v1/emails/send`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': `Bearer ${p.apiKey}`,
      ...(p.idempotencyKey ? { 'Idempotency-Key': p.idempotencyKey } : {}),
    },
    body: JSON.stringify({ to: p.to, subject: p.subject, content: p.content, htmlContent: p.htmlContent, policyKey: p.policyKey })
  });
  const body = await res.json();
  if (!res.ok) throw Object.assign(new Error(body?.message || body?.error || 'Request failed'), { response: body });
  return { data: body, requestId: res.headers.get('Fluxomail-Request-Id') };
}
Python (requests)
import os, uuid, requests

def send_email(api_key: str, to: str, subject: str, content: str, html: str | None = None, idem: str | None = None):
    base = 'https://api.fluxomail.com'
    headers = { 'Authorization': f'Bearer {api_key}' }
    if idem: headers['Idempotency-Key'] = idem
    r = requests.post(f"{base}/api/v1/emails/send", headers=headers, json={
        'to': to, 'subject': subject, 'content': content, 'htmlContent': html
    })
    r.raise_for_status()
    return { 'data': r.json(), 'request_id': r.headers.get('Fluxomail-Request-Id') }
OpenAPI
  • Download the OpenAPI spec to generate clients for other languages: /api-reference/openapi.fluxomail.json
Typed subscribe (narrowed handler)
// When you specify concrete event types, the handler is narrowed accordingly
fm.events.subscribe({ types: ['email.delivered', 'email.opened'] }, (evt) => {
  // evt is EmailEventEnvelope<'email.delivered' | 'email.opened'>
})
SSE callbacks and backoff
const sub = fm.events.subscribe({
  types: ['email.*'],
  onOpen: () => console.log('connected'),
  onError: (e) => console.log('sse error', e),
  onReconnect: (attempt, delay) => console.log('reconnecting', { attempt, delay }),
  backoff: { baseDelayMs: 100, maxDelayMs: 1000 },
}, (evt) => {/* ... */})
Templates (beta)
// Create and render a template
const t = await fm.templates.create({ name: 'Welcome', subject: 'Hi {{name}}', htmlContent: '<h1>Hi {{name}}</h1>' })
const rendered = await fm.templates.render(t.id, { variables: { name: 'Pat' } })
// Manage
await fm.templates.update(t.id, { subject: 'Hello {{name}}' })
const list = await fm.templates.list({ limit: 10 })
await fm.templates.delete(t.id)
Webhooks (optional; server only)
import { webhooks } from '@fluxomail/sdk'

export async function handler(req, res) {
  const raw = await getRawBody(req) // raw string
  const ok = webhooks.verifyHmacSignature(raw, req.headers, { secret: process.env.FLUXOMAIL_WEBHOOK_SECRET! })
  if (!ok) return res.status(401).end('invalid signature')
  const out = webhooks.verifyAndParse(raw, req.headers, { secret: process.env.FLUXOMAIL_WEBHOOK_SECRET! })
  for (const evt of out.events) {
    // handle
  }
  res.status(200).end('ok')
}