Guide

Bill without double billing

Raise exactly one invoice per customer per billing period, however many times your job runs or retries.

Scope: invoices:write.

Choose a deterministic externalRef#

Build externalRef from what you're billing: your customer id and the period, such as ws_42-2026-11. The same customer and month always give the same reference. Flux never raises two invoices with one reference, permanently, so a rerun or a retry returns the invoice that already exists.

BillingExample externalRef
Monthly subscriptionws_42-2026-11
Quarterly subscriptionws_42-2026-Q4
One-off setup feews_42-setup
Usage for a periodws_42-usage-2026-11

At most 100 characters.

Raise the invoice#

// Raises the invoice for one customer and month. Safe to run any number of times.
export async function billMonth(customer, year, month) {
  const period = `${year}-${String(month).padStart(2, "0")}`;            // "2026-11"
  const externalRef = `ws_${customer.workspaceId}-${period}`;            // "ws_42-2026-11"
  const lastDay = new Date(Date.UTC(year, month, 0)).getUTCDate();

  const res = await fetch(`${process.env.FLUX_BASE_URL}/api/v1/invoices`, {
    method: "POST",
    headers: {
      Authorization: `ApiKey ${process.env.FLUX_API_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": `invoice-${externalRef}`,
    },
    body: JSON.stringify({
      externalRef,
      customerId: customer.fluxId,
      currency: "NGN",
      dueDate: `${period}-15`,
      periodStart: `${period}-01`,
      periodEnd: `${period}-${lastDay}`,
      invoiceType: "subscription",
      lines: [
        { serviceId: 7, quantity: customer.entityCount, unitPrice: 250000, detail: `${customer.entityCount} entities` },
      ],
    }),
  });

  if (res.status === 201) return { invoice: await res.json(), created: true };
  if (res.status === 200) return { invoice: await res.json(), created: false };  // already raised
  throw new Error(`${res.status} ${await res.text()}`);
}
  • 201: a new invoice. Save its id against your period.
  • 200: one already exists for this reference. Flux returns it as it is now and changes nothing, even if your amounts differ. If they do, a person needs to fix the invoice in Flux.

Lines and amounts#

  • For per-unit pricing, send quantity and unitPrice. Flux multiplies and rounds to 2 decimals, and the line reads “Subscription — 3 entities (3 × 250,000.00)”.
  • For a fixed amount, send amount.
  • You can't send a total. Flux adds the lines, takes off discount, and applies the organization's VAT.

Remember approval#

A new invoice is awaiting_approval. The customer gets nothing until someone approves it in Flux. Listen for invoice.approved or invoice.issued to know when it has gone out, and for invoice.returned if a reviewer sends it back.

A returned invoice is fixed and resubmitted in Flux; don't raise a new one. If an invoice is voided and you need to bill the period again, use a new reference, such as ws_42-2026-11-r2.