Skip to content

Invoices you bill customers for, from draft to paid.

6 endpoints, each with the fields it takes and the fields it gives back.

GET/invoices

Lists customer invoices for one business, newest first.

  • Leave entityId out only when this key can reach exactly one business. When it can reach several, a call that omits it is refused; call GET /businesses for the ids.
  • dateFrom and dateTo match the issue date and include both ends.
  • To read the next page, pass the previous response's nextCursor. A null there means you already have everything.
  • overdueOnly is applied to the page you asked for, not to the whole list, so a page can come back with fewer rows than limit, or none, while nextCursor is still set.
  • An invoice's figures are in the invoice's own currency, which may not be US dollars, and the currency beside each figure says which. Every other amount on this surface is US dollars.

Needs the invoices:read permission. A Read only key has it.

Query parameters

entityId
Typestring
RequiredOptional
Details
  • a uuid
status
Typestring
RequiredOptional
Details
  • one of: draft, sent, viewed, partially_paid, paid, overdue, void
customerId
Typestring
RequiredOptional
Details
  • a uuid
dateFrom
Typestring
RequiredOptional
Details
  • a date like 2026-09-20
dateTo
Typestring
RequiredOptional
Details
  • a date like 2026-09-20
overdueOnly
Typestring
RequiredOptional
Details
  • one of: true, false
cursor
Typestring
RequiredOptional
Details
  • an opaque value from a previous response
limit
Typeinteger
RequiredOptional
Details
  • 1 to 100, default 50
Request
curl "https://www.numm.io/api/v1/invoices?entityId=0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f1002&status=sent" \
  -H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY"
Response 200
{
  "invoices": [
    {
      "id": "0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007",
      "number": "ACME-0001",
      "status": "sent",
      "customer": "Acme Co",
      "issueDate": "2026-06-01",
      "dueDate": "2026-06-15",
      "total": {
        "cents": "10000",
        "formatted": "$100.00",
        "currency": "USD"
      },
      "paid": {
        "cents": "0",
        "formatted": "$0.00",
        "currency": "USD"
      },
      "balance": {
        "cents": "10000",
        "formatted": "$100.00",
        "currency": "USD"
      },
      "currency": "USD"
    }
  ],
  "nextCursor": null
}

Response fields

invoices
Typearray of object
PresentAlways
invoices[].id
Typestring
PresentAlways
Details
  • a uuid
invoices[].number
Typestring
PresentAlways
invoices[].status
Typestring
PresentAlways
Details
  • one of: draft, sent, viewed, partially_paid, paid, overdue, void
invoices[].customer
Typestring
PresentAlways
invoices[].issueDate
Typestring
PresentAlways
Details
  • a date like 2026-09-20
invoices[].dueDate
Typestring
PresentAlways
Details
  • a date like 2026-09-20
invoices[].total
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
invoices[].paid
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
invoices[].balance
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
invoices[].currency
Typestring
PresentAlways
Details
  • one of: USD, CAD, EUR, GBP, MXN
nextCursor
Typestring or null
PresentAlways
Details
  • an opaque value from a previous response

Errors

entity_not_allowed
Status403
MeaningYour key is limited to certain businesses, and this is not one of them.
not_found
Status404
MeaningThere is no such record, or none your key can reach.

Every endpoint can also return:

invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.

GET/invoices/{id}

Returns full detail for one invoice, including its lines, payments, and pay link.

  • An invoice's figures are in the invoice's own currency, which may not be US dollars, and the currency beside each figure says which. Every other amount on this surface is US dollars.
  • payUrl is the customer's own pay page and needs no sign-in. Anyone with the link can open the invoice and pay it, so treat it like the invoice email itself.

Needs the invoices:read permission. A Read only key has it.

Path parameters

id
Typestring
RequiredRequired
Details
  • a uuid
Request
curl "https://www.numm.io/api/v1/invoices/0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007" \
  -H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY"
Response 200
{
  "id": "0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007",
  "number": "ACME-0001",
  "status": "sent",
  "customer": {
    "id": "0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1005",
    "name": "Acme Co"
  },
  "issueDate": "2026-06-01",
  "dueDate": "2026-06-15",
  "terms": "Net 15",
  "currency": "USD",
  "subtotal": {
    "cents": "10000",
    "formatted": "$100.00",
    "currency": "USD"
  },
  "tax": {
    "cents": "0",
    "formatted": "$0.00",
    "currency": "USD"
  },
  "total": {
    "cents": "10000",
    "formatted": "$100.00",
    "currency": "USD"
  },
  "paid": {
    "cents": "0",
    "formatted": "$0.00",
    "currency": "USD"
  },
  "balance": {
    "cents": "10000",
    "formatted": "$100.00",
    "currency": "USD"
  },
  "memo": null,
  "lines": [
    {
      "description": "Consulting",
      "quantity": "1",
      "unitPrice": {
        "cents": "10000",
        "formatted": "$100.00",
        "currency": "USD"
      },
      "amount": {
        "cents": "10000",
        "formatted": "$100.00",
        "currency": "USD"
      },
      "account": "Consulting Revenue"
    }
  ],
  "payments": [],
  "payUrl": "https://www.numm.io/pay/abc123"
}

Response fields

id
Typestring
PresentAlways
Details
  • a uuid
number
Typestring
PresentAlways
status
Typestring
PresentAlways
Details
  • one of: draft, sent, viewed, partially_paid, paid, overdue, void
customer
Typeobject
PresentAlways
customer.id
Typestring
PresentAlways
Details
  • a uuid
customer.name
Typestring
PresentAlways
issueDate
Typestring
PresentAlways
Details
  • a date like 2026-09-20
dueDate
Typestring
PresentAlways
Details
  • a date like 2026-09-20
terms
Typestring or null
PresentAlways
currency
Typestring
PresentAlways
Details
  • one of: USD, CAD, EUR, GBP, MXN
subtotal
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
tax
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
total
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
paid
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
balance
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
memo
Typestring or null
PresentAlways
lines
Typearray of object
PresentAlways
lines[].description
Typestring
PresentAlways
lines[].quantity
Typestring
PresentAlways
lines[].unitPrice
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
lines[].amount
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
lines[].account
Typestring
PresentAlways
payments
Typearray of object
PresentAlways
payments[].amount
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)
payments[].method
Typestring
PresentAlways
Details
  • one of: stripe, check, cash, wire, other
payments[].paidAt
Typestring
PresentAlways
Details
  • a date like 2026-09-20
payUrl
Typestring
PresentAlways

Errors

not_found
Status404
MeaningThere is no such record, or none your key can reach.

Every endpoint can also return:

invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.

POST/invoices

Creates a draft invoice for a customer. Nothing is sent and nothing is emailed.

  • Leave entityId out only when this key can reach exactly one business. When it can reach several, a call that omits it is refused; call GET /businesses for the ids.
  • unitPriceCents is whole cents, and quantity allows up to six decimal places. Each line's quantity must be greater than zero.
  • issueDate defaults to the current date in UTC. dueDate defaults to issueDate plus the payment terms, taken from the customer, then the business, then your account. A dueDate before issueDate is refused.
  • Every line amount, the subtotal, and the total must each stay under ten trillion dollars.
  • currency is the invoice's own currency, and defaults to US dollars when you leave it out. It is not taken from the customer, even when the customer is set to another currency, which is how the app's own invoice form behaves too.
  • unitPriceCents, and every figure the invoice reads back with, are cents of the invoice's own currency. Your books stay in US dollars: the conversion happens when the invoice is sent.
  • Sending an invoice in another currency needs an exchange rate for its issue date. Until one has been fetched, POST /invoices/{id}/send is refused with validation_failed and the draft is left as it is.

Needs the invoices:write permission. Only a Read and write key has it.

Body fields

entityId
Typestring
RequiredOptional
Details
  • a uuid
customerId
Typestring
RequiredRequired
Details
  • a uuid
issueDate
Typestring
RequiredOptional
Details
  • a date like 2026-09-20
paymentTermsDays
Typeinteger
RequiredOptional
Details
  • 0 to 365
dueDate
Typestring
RequiredOptional
Details
  • a date like 2026-09-20
lines
Typearray of object
RequiredRequired
lines[].description
Typestring
RequiredRequired
Details
  • up to 2000 characters
lines[].quantity
Typestring
RequiredRequired
Details
  • a number, up to 6 decimal places
lines[].unitPriceCents
Typestring
RequiredRequired
Details
  • digits only, whole cents
lines[].accountId
Typestring
RequiredRequired
Details
  • a uuid
currency
Typestring
RequiredOptional
Details
  • one of: USD, CAD, EUR, GBP, MXN
taxRatePercent
Typestring
RequiredOptional
Details
  • a percentage from 0 to 100, up to 6 decimal places
memo
Typestring
RequiredOptional
Details
  • up to 2000 characters
Request
curl -X POST "https://www.numm.io/api/v1/invoices" \
  -H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0190a1b2-c3d4-7e5f-8a9b-0c1d2e3fee00" \
  -d '{
  "entityId": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f1002",
  "customerId": "0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1005",
  "lines": [
    {
      "description": "Consulting",
      "quantity": "1",
      "unitPriceCents": "10000",
      "accountId": "0190a1b2-c3d4-7e5f-8a9b-0c1d2e3f1003"
    }
  ]
}'
Response 201
{
  "invoiceId": "0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007",
  "invoiceNumber": "ACME-0001",
  "webUrl": "https://www.numm.io/app/invoices/0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007"
}

Response fields

invoiceId
Typestring
PresentAlways
Details
  • a uuid
invoiceNumber
Typestring
PresentAlways
webUrl
Typestring
PresentAlways

This call takes an optional Idempotency-Key header. Repeat the same request with the same key within 24 hours and you get the first response back, with an idempotent-replayed: true header, and the work does not run twice. The same key with a different request is refused. See Idempotency and safe retries.

Errors

entity_not_allowed
Status403
MeaningYour key is limited to certain businesses, and this is not one of them.
not_found
Status404
MeaningThere is no such record, or none your key can reach.
conflict
Status409
MeaningThe request clashed with something that already happened.

Every endpoint can also return:

invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.

POST/invoices/{id}/send

Finalizes a draft invoice and emails it to the customer.

  • Finalizing posts the invoice to the books and emails the customer before this call returns.
  • There is no API call that undoes it.
  • An invoice drafted in a currency other than US dollars needs an exchange rate for its issue date. Without one this call is refused with validation_failed, and the draft is left as it was. Try again once the day's rate has been fetched.

Needs the invoices:write permission. Only a Read and write key has it.

Path parameters

id
Typestring
RequiredRequired
Details
  • a uuid

No request body.

Request
curl -X POST "https://www.numm.io/api/v1/invoices/0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007/send" \
  -H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY" \
  -H "Idempotency-Key: 0190a1b2-c3d4-7e5f-8a9b-0c1d2e3fee00"
Response 200
{
  "ok": true
}

Response fields

ok
Typeboolean
PresentAlways
Details
  • always true

This call takes an optional Idempotency-Key header. Repeat the same request with the same key within 24 hours and you get the first response back, with an idempotent-replayed: true header, and the work does not run twice. The same key with a different request is refused. See Idempotency and safe retries.

Errors

not_found
Status404
MeaningThere is no such record, or none your key can reach.
period_locked
Status409
MeaningThe date falls inside a closed period, so nothing can post to it.
read_only_billing_state
Status402
MeaningYour subscription is past due, so your books are read only for now.
conflict
Status409
MeaningThe request clashed with something that already happened.

Every endpoint can also return:

invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.

POST/invoices/{id}/remind

Sends a payment reminder email for one sent (or overdue) invoice.

  • The invoice has to be sent, viewed, or overdue, and the customer has to have an email address.
  • A second reminder for the same invoice within 24 hours is refused with conflict.

Needs the invoices:write permission. Only a Read and write key has it.

Path parameters

id
Typestring
RequiredRequired
Details
  • a uuid

No request body.

Request
curl -X POST "https://www.numm.io/api/v1/invoices/0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007/remind" \
  -H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY" \
  -H "Idempotency-Key: 0190a1b2-c3d4-7e5f-8a9b-0c1d2e3fee00"
Response 200
{
  "ok": true
}

Response fields

ok
Typeboolean
PresentAlways
Details
  • always true

This call takes an optional Idempotency-Key header. Repeat the same request with the same key within 24 hours and you get the first response back, with an idempotent-replayed: true header, and the work does not run twice. The same key with a different request is refused. See Idempotency and safe retries.

Errors

not_found
Status404
MeaningThere is no such record, or none your key can reach.
conflict
Status409
MeaningThe request clashed with something that already happened.

Every endpoint can also return:

invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.

POST/invoices/{id}/payments

Records a payment received against a sent invoice: check, cash, wire, or other.

  • amountCents must be greater than zero, and may not exceed the remaining balance.
  • The invoice has to have been sent already, and must not be fully paid.
  • method defaults to other, and paidAt defaults to the current date in UTC.
  • method covers the payments you take yourself. Card payments arrive through Stripe and post on their own.
  • The balance in the response leaves out any payment that was refunded.
  • amountCents and the balance in the response are in the invoice's own currency, which may not be US dollars. Every other amount on this surface is US dollars.

Needs the invoices:write permission. Only a Read and write key has it.

Path parameters

id
Typestring
RequiredRequired
Details
  • a uuid

Body fields

amountCents
Typestring
RequiredRequired
Details
  • digits only, whole cents
paidAt
Typestring
RequiredOptional
Details
  • a date like 2026-09-20
method
Typestring
RequiredOptional
Details
  • one of: check, cash, wire, other
memo
Typestring
RequiredOptional
Details
  • up to 2000 characters
Request
curl -X POST "https://www.numm.io/api/v1/invoices/0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1007/payments" \
  -H "Authorization: Bearer nmo_live_REPLACE_WITH_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 0190a1b2-c3d4-7e5f-8a9b-0c1d2e3fee00" \
  -d '{
  "amountCents": "4000",
  "method": "check"
}'
Response 200
{
  "paymentId": "0190a1b2-c3d4-7e5f-9a9b-0c1d2e3f1009",
  "status": "partially_paid",
  "balance": {
    "cents": "6000",
    "formatted": "$60.00",
    "currency": "USD"
  }
}

Response fields

paymentId
Typestring
PresentAlways
Details
  • a uuid
status
Typestring
PresentAlways
Details
  • one of: draft, sent, viewed, partially_paid, paid, overdue, void
balance
Typemoney
PresentAlways
Details
  • an object: cents (whole cents as a digit string, in the currency beside it), formatted (a display string, not something to parse), currency (a three-letter code)

This call takes an optional Idempotency-Key header. Repeat the same request with the same key within 24 hours and you get the first response back, with an idempotent-replayed: true header, and the work does not run twice. The same key with a different request is refused. See Idempotency and safe retries.

Errors

not_found
Status404
MeaningThere is no such record, or none your key can reach.
period_locked
Status409
MeaningThe date falls inside a closed period, so nothing can post to it.
read_only_billing_state
Status402
MeaningYour subscription is past due, so your books are read only for now.
conflict
Status409
MeaningThe request clashed with something that already happened.

Every endpoint can also return:

invalid_key
Status401
MeaningYour key is missing, malformed, revoked, or expired.
insufficient_scope
Status403
MeaningYour key does not carry the scope this endpoint needs.
rate_limited
Status429
MeaningYou've made too many requests for this key. The retry-after header says how long to wait.
validation_failed
Status422
MeaningSomething in the path, the query, or the body did not pass validation.
internal_error
Status500
MeaningSomething went wrong on our side. Try again.
Invoices — Nummio API