POST
/api/public/v1/invoices

Create an invoice

Raises an invoice. It starts OPEN and is **not sent** — mail the pay link separately once you are ready. Two rules callers trip over: the amount due now must clear Stripe’s 50-cent minimum, so at least one line has to be `dueNow`; and every recurring line must share one interval, count and installment length, because a Stripe subscription bills all of its items on a single cycle.

Required scope

The access token must carry this scope. A token missing it gets 403 Forbidden. Grant them to an API client under Settings → Company → API, and to a teammate under Employee → Permissions.

invoices:write

Request Body

PropertyTypeDescription
legalEntityIdstringWhich entity is invoicing. Must be one the token can reach.
memostringWhat the invoice is for.
lineItemsarrayAt least one `{ description, quantity, unitAmount, kind }`. `kind` is ONE_TIME or RECURRING; a RECURRING line also needs `interval` (WEEK/MONTH/YEAR), and takes `intervalCount` and `installments` (omit for ongoing). `unitAmount` is cents.
counterpartyNamestringWho is being billed.
counterpartyEmailstringWhere the pay link is emailed. Required before you can send it.
notesstring
dueDatestringISO 8601.
POSTExample request
curl
curl -X POST "https://www.pxb.app/api/public/v1/invoices" \
  -H "Authorization: Bearer your_access_token" \
  -H "Content-Type: application/json" \
  -d '{
    "legalEntityId": "le_7788",
    "memo": "Website build — phase one",
    "counterpartyName": "Northwind Traders",
    "counterpartyEmail": "ap@northwind.example",
    "lineItems": [
      {
        "description": "Design and build",
        "quantity": 1,
        "unitAmount": 250000,
        "kind": "ONE_TIME",
        "dueNow": true
      }
    ]
  }'
200Example response
json
{
  "message": "Invoice created!",
  "content": {
    "invoice": {
      "id": "9f1c2f4e-6b3a-4f28-9c11-0a2b3c4d5e6f",
      "referenceId": 1042,
      "status": "OPEN",
      "counterpartyName": "Northwind Traders",
      "counterpartyEmail": "ap@northwind.example",
      "memo": "Website build — phase one",
      "notes": null,
      "dueDate": "2026-09-30T00:00:00.000Z",
      "dueNowAmount": 250000,
      "currency": "usd",
      "legalEntityId": "le_7788",
      "lineItems": [
        {
          "id": "ili_1",
          "description": "Design and build",
          "quantity": 1,
          "unitAmount": 250000,
          "kind": "ONE_TIME",
          "dueNow": true,
          "sortOrder": 0
        },
        {
          "id": "ili_2",
          "description": "Hosting and support",
          "quantity": 1,
          "unitAmount": 15000,
          "kind": "RECURRING",
          "dueNow": true,
          "interval": "MONTH",
          "intervalCount": 1,
          "installments": 12,
          "sortOrder": 1
        }
      ],
      "viewedAt": null,
      "paidAt": null,
      "createdAt": "2026-08-22T15:00:00.000Z",
      "updatedAt": "2026-08-22T15:00:00.000Z"
    }
  }
}
400Example response
json
{
  "message": "The amount due now must be at least $0.50. Mark a line item as due now."
}

In the console

The same thing done by hand, for anyone comparing the API against the screen they already use.

Finances → Receivables
/finances/receivables
  1. Open Receivables.
  2. New invoice.
  3. Add line items and save.