Creating Invoices

Issue invoices for one customer or all customers at once.

Invoice Basics

An invoice is ABAXUS’s final billing artifact — the output of running the billing engine for a customer over a specific period. Invoices in ABAXUS are always derived from subscriptions and their associated usage events; you cannot create a free-form invoice for an arbitrary amount (use your payment provider for that).

When you create an invoice, ABAXUS:

  1. Finds all active subscriptions for the customer as of the cutoff_date
  2. Derives period_start from the subscription’s start_date and billing period (monthly, annual, etc.)
  3. Aggregates usage events that occurred between period_start and cutoff_date
  4. Applies the subscription’s pinned plan version pricing rules
  5. Returns an invoice object with full line items

POST /v1/invoices — Single Invoice

Create an invoice for one customer at a specific cutoff date:

1
2
3
4
5
6
7
curl -X POST "$ABAXUS_URL/v1/invoices" \
  -H "Authorization: Bearer $ABAXUS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "cust_acme",
    "cutoff_date": "2026-04-30T23:59:59Z"
  }'

Response:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
{
  "id": "inv_01hx9kr2s3t4u5v6w7x8y9z0",
  "customer_id": "cust_acme",
  "status": "issued",
  "currency": "usd",
  "total_amount": 18749,
  "period_start": "2026-04-01T00:00:00Z",
  "period_end": "2026-04-30T23:59:59Z",
  "line_items": [
    {
      "description": "Growth base fee",
      "pricing_model": "flat_fee",
      "amount": 4900
    },
    {
      "description": "API Calls — 1,374,923 calls",
      "pricing_model": "tiered",
      "metric_key": "api_calls",
      "amount": 13849,
      "tier_breakdown": [...]
    },
    {
      "description": "Data Egress — 142.75 GB",
      "pricing_model": "per_unit",
      "metric_key": "data_egress_gb",
      "amount": 1142
    }
  ],
  "created_at": "2026-04-03T11:00:00Z"
}

The cutoff_date is the end of the billing period. ABAXUS uses the subscription’s start_date and billing_period to derive period_start automatically. For a subscription that started on April 1 with monthly billing, a cutoff_date of April 30 produces a period from April 1 to April 30.

Using a Pre-Calculated Amount

If you’ve already run POST /v1/pricing/calculate and want the invoice to use those exact amounts (avoiding a second computation):

1
2
3
4
5
6
7
8
curl -X POST "$ABAXUS_URL/v1/invoices" \
  -H "Authorization: Bearer $ABAXUS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "customer_id": "cust_acme",
    "cutoff_date": "2026-04-30T23:59:59Z",
    "calculation_id": "calc_01hx9kq2r3s4t5u6v7w8x9y0"
  }'

Passing calculation_id skips the billing computation step and uses the pre-calculated line items directly. The calculation must be less than 24 hours old.


POST /v1/invoices/bulk — All Active Customers

The bulk endpoint creates invoices for all customers with active subscriptions at the cutoff_date. This is the endpoint you’d call at the end of each billing period to run your monthly billing cycle:

1
2
3
4
5
6
curl -X POST "$ABAXUS_URL/v1/invoices/bulk" \
  -H "Authorization: Bearer $ABAXUS_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "cutoff_date": "2026-04-30T23:59:59Z"
  }'

Response:

1
2
3
4
5
6
7
8
{
  "job_id": "job_01hx9ks3t4u5v6w7x8y9z0a",
  "status": "running",
  "total_customers": 847,
  "invoices_created": 0,
  "invoices_skipped": 0,
  "errors": 0
}

Bulk invoicing runs asynchronously. Poll GET /v1/jobs/:job_id to track progress. When complete:

1
2
3
4
5
6
7
8
9
{
  "job_id": "job_01hx9ks3t4u5v6w7x8y9z0a",
  "status": "completed",
  "total_customers": 847,
  "invoices_created": 831,
  "invoices_skipped": 16,
  "errors": 0,
  "completed_at": "2026-04-30T23:14:22Z"
}

invoices_skipped includes customers where the computed total was zero. ABAXUS skips zero-amount invoices by default to avoid unnecessary Stripe charges. Pass include_zero_amount: true to override this behavior.


Invoice Idempotency

Invoice creation is idempotent per customer per billing period. If you call POST /v1/invoices for the same customer and the same period twice, ABAXUS returns the existing invoice rather than creating a duplicate. This means you can safely retry invoice creation after a timeout without risk of double-billing.

ABAXUS determines the billing period from the subscription’s start date and billing_period type, not from the cutoff_date directly. Two requests with cutoff_date: "2026-04-30" and cutoff_date: "2026-04-28" that both resolve to the April 1–30 period will reference the same invoice (if one already exists).


Invoice Lifecycle

An invoice moves through the following states:

issued → paid
         ↓
     archived
  • issued: The invoice has been created with calculated amounts. It can be viewed, downloaded, emailed, and charged.
  • paid: A successful charge has been processed. The invoice is closed and cannot be modified.
  • archived: The invoice has been manually archived (e.g., for zero-amount invoices, write-offs, or dispute resolutions). Archived invoices are closed without payment.

Only issued invoices can be charged. Attempting to charge a paid or archived invoice returns a 409 Conflict.


Listing Invoices

1
2
3
4
5
6
7
# All invoices for a customer
curl "$ABAXUS_URL/v1/invoices?customer_id=cust_acme&status=issued" \
  -H "Authorization: Bearer $ABAXUS_KEY"

# All invoices across all customers
curl "$ABAXUS_URL/v1/invoices?status=issued&limit=50" \
  -H "Authorization: Bearer $ABAXUS_KEY"