Invoices
An invoice records billed products or services, taxes, payments, and the amount still due from a customer. API v3 can create, safely update, dispatch, cancel, and delete eligible invoices, retrieve existing invoices, record manual payments, and list payment history.
The invoice object
| Field | Type | Description |
|---|---|---|
id | string | Unique invoice UUID. |
object | string | Always invoice. |
invoice_number | integer | Account-assigned invoice number. |
custom_invoice_number | string or null | Optional custom invoice number. |
name | string or null | Invoice name. |
customer_id | string | Customer UUID. |
customer_name | string | Customer display name stored with the invoice. |
salesperson_id | string | Assigned SalesBinder user UUID. |
status_id | integer | Current invoice status identifier. |
status | string or null | Current invoice status name. |
issue_date | string or null | Invoice issue date in YYYY-MM-DD format. |
expiry_date | string or null | Stored invoice expiry date in YYYY-MM-DD format. |
date_sent | string or null | Date sent in YYYY-MM-DD format. |
date_fully_paid | string or null | Date fully paid in YYYY-MM-DD format. |
purchase_order_number | string | Customer purchase-order reference. |
attention | string or null | Attention line. |
shipping_address | string or null | Shipping-address text stored on the invoice. |
public_note | string or null | Customer-facing invoice note. |
payment_terms | string or null | Payment terms stored on the invoice. |
subtotal | string | Subtotal before shipping and taxes, as a four-decimal string. |
shipping | string | Shipping charge as a four-decimal string. |
tax | string | Primary tax amount as a four-decimal string. |
tax_2 | string | Secondary tax amount as a four-decimal string. |
total | string | Invoice total including shipping and taxes, as a four-decimal string. |
amount_paid | string | Recorded payments as a four-decimal string. |
amount_due | string | Remaining amount due as a four-decimal string. |
shipped_percent | integer or null | Percentage shipped. |
created_at | string or null | ISO 8601 creation timestamp. |
updated_at | string or null | ISO 8601 modification timestamp. |
lines | array | Current invoice line objects. Present only when retrieving one invoice. |
Monetary values use the SalesBinder account's base currency. Cost and margin values are not included in invoice API responses.
The invoice line object
| Field | Type | Description |
|---|---|---|
id | string | Unique invoice-line UUID. |
object | string | Always invoice_line. |
item_id | string or null | Related inventory item UUID, when present. |
name | string or null | Line-item name. |
description | string or null | Line-item description. |
quantity | number | Billed quantity. |
unit_id | integer or null | Related unit identifier. |
unit_price | string | Original unit price as a four-decimal string. |
discount_percent | string | Discount percentage as a three-decimal string. |
discounted_unit_price | string or null | Discounted unit price, or null when no discounted price is stored. |
tax_rate | string | Primary tax percentage as a three-decimal string. |
tax_2_rate | string | Secondary tax percentage as a three-decimal string. |
subtotal | string | Quantity multiplied by the effective unit price, before tax, as a four-decimal string. |
Line-item unit costs are intentionally omitted.
The payment object
| Field | Type | Description |
|---|---|---|
id | string | Unique payment or refund transaction UUID. |
object | string | Always payment. |
invoice_id | string | UUID of the related invoice. |
amount | string | Signed transaction amount as a four-decimal string. Refunds are negative. |
type | string | payment for a non-negative amount or refund for a negative amount. |
reference | string or null | Manual or provider payment reference. |
payment_date | string or null | Transaction date in YYYY-MM-DD format. |
card | object or null | Limited card summary when stored, otherwise null. |
card.brand | string or null | Card brand when stored. |
card.last4 | string or null | Last four card digits when stored. |
The response includes only the payment fields listed above.
Create an invoice
POST/api/v3/invoices
Required scope: invoices:write
Creates an unpaid invoice assigned to the API key's current user. The response is the new invoice object with its calculated line items. Creating an invoice does not send it to the customer, record a payment, or mark anything as fulfilled.
Invoices can also be created from an existing open estimate through POST/api/v3/estimates/{estimate_id}/convert-to-invoice. That dedicated action preserves the estimate relationship and closes the estimate as part of the same operation.
Request fields
| Field | Type | Required | Description |
|---|---|---|---|
customer_id | string | Yes | Active customer UUID in the current SalesBinder account. |
lines | array | Yes | One to 100 inventory or service line objects. |
name | string | No | Optional name for your own reference. |
issue_date | string | No | Issue date in YYYY-MM-DD format. Defaults using the account and user timezone. |
custom_invoice_number | string | No | Optional custom reference, up to 24 characters. |
purchase_order_number | string | No | Customer purchase-order reference. |
attention | string | No | Attention line. |
shipping_address | string | No | Shipping-address text. |
public_note | string | No | Customer-facing note. |
payment_terms | string | No | Payment terms. Account defaults apply when omitted. |
shipping | number | No | Shipping charge. Defaults to 0. |
discount_percent | number | No | Invoice-wide discount from 0 to 100. |
Line fields
| Field | Type | Required | Description |
|---|---|---|---|
item_id | string | Inventory lines | Active inventory item UUID. The API copies its name, description, cost, and permitted selling price. |
item_variation_location_id | integer | Variation items | Variation-location identifier belonging to the selected item and account. |
name | string | Service lines | Service line name. Ignored for inventory lines. |
description | string | No | Service line description. Inventory descriptions come from the item. |
quantity | number | No | Positive quantity. Defaults to 1; unique items are always 1. |
unit_price | number | Service lines | Required for service lines. Optional for inventory lines only when the current user may modify selling prices. |
tax_rate | number | No | Primary tax percentage from 0 to 100; defaults to the customer's rate. |
tax_2_rate | number | No | Secondary tax percentage from 0 to 100; defaults to the customer's rate. |
Invoice number, status, salesperson, account, source, totals, costs, payments, fulfillment state, and timestamps are controlled by SalesBinder. Supplying unsupported or protected fields returns 422 unsupported_invoice_field rather than silently accepting them.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/invoices" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: warehouse-invoice-1042" \
--data '{
"customer_id": "709d2a43-12a9-4d85-a9d9-cb16e66cef53",
"issue_date": "2026-07-18",
"shipping": 10,
"discount_percent": 5,
"lines": [
{
"item_id": "c420fb4b-e98e-4ed4-b2e9-7ad8cc970966",
"quantity": 2
},
{
"name": "Installation",
"quantity": 1,
"unit_price": 75,
"tax_rate": 5
}
]
}'The invoice and its number are saved together. A failed request does not consume an invoice number.
Update an invoice
PATCH/api/v3/invoices/{invoice_id}
Required scope: invoices:write
Updates supported fields on an unpaid invoice. Include only the top-level fields that should change. SalesBinder recalculates totals, taxes, discounts, inventory effects, and other protected values automatically.
The supported top-level fields are the same as invoice creation. customer_id may be changed only when a complete lines replacement is also supplied.
Replacing invoice lines
When lines is omitted, the current active lines are preserved. When lines is supplied, it is the complete replacement for all active non-discount lines:
- Include an existing line's
idto replace that line while preserving its identity. - Omit
idto create a new line. - Any current active line omitted from the array is removed from the invoice.
- Do not submit discount line IDs. Set the top-level
discount_percentfield to change or remove the invoice-wide discount.
Line IDs must belong to the invoice being updated. A deleted line, a line from another invoice, or a duplicated line ID is rejected.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513" \
--request PATCH \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: warehouse-invoice-1042-update-1" \
--data '{
"shipping": 12,
"public_note": "Thank you for your business.",
"discount_percent": 5,
"lines": [
{
"id": "34ed0d15-8748-40b2-89d4-482466996234",
"name": "Installation",
"quantity": 2,
"unit_price": 75,
"tax_rate": 5
},
{
"item_id": "c420fb4b-e98e-4ed4-b2e9-7ad8cc970966",
"quantity": 1
}
]
}'An Idempotency-Key is optional but recommended for update requests. SalesBinder temporarily replays the completed response for a quick retry with the same key and payload, while rejecting reuse of that key with different data.
List invoices
GET/api/v3/invoices
Required scope: invoices:read
Invoices linked to one sales order can also be listed through GET/api/v3/sales-orders/{sales_order_id}/invoices. That nested collection additionally requires sales_orders:read and applies both resources' visibility boundaries.
Returns visible active invoices ordered by invoice number, newest first. Line items are omitted from list responses.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number. Defaults to 1. |
limit | integer | No | Records per page. Defaults to 20; maximum 100. |
q | string | No | Searches customer name, custom invoice number, and invoice name. A numeric value also matches an exact invoice number. |
customer_id | string | No | Returns invoices for the customer UUID. |
status_id | integer | No | Returns invoices with the status identifier. |
issue_date_from | string | No | Includes invoices issued on or after this YYYY-MM-DD date. |
issue_date_to | string | No | Includes invoices issued on or before this YYYY-MM-DD date. |
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/invoices?customer_id=709d2a43-12a9-4d85-a9d9-cb16e66cef53&limit=20" \
--header "Authorization: Bearer YOUR_API_KEY"Example response
{
"object": "list",
"url": "/api/v3/invoices",
"has_more": false,
"data": [
{
"id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"object": "invoice",
"invoice_number": 1042,
"customer_id": "709d2a43-12a9-4d85-a9d9-cb16e66cef53",
"customer_name": "Example Customer",
"status_id": 9,
"status": "Sent",
"issue_date": "2026-07-18",
"subtotal": "100.0000",
"shipping": "10.0000",
"tax": "5.5000",
"tax_2": "2.2000",
"total": "117.7000",
"amount_paid": "50.0000",
"amount_due": "67.7000"
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total_pages": 1,
"total_records": 1
}
}Examples may omit unchanged fields for readability.
Retrieve an invoice
GET/api/v3/invoices/{invoice_id}
Required scope: invoices:read
Returns one visible active invoice. The response includes the lines array, ordered by the invoice's stored line order. Deleted lines are excluded.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513" \
--header "Authorization: Bearer YOUR_API_KEY"If the invoice is outside the current account or assigned-user boundary, is not an invoice, has been archived, or does not exist, the API returns 404 resource_missing.
Record an invoice payment
POST/api/v3/invoices/{invoice_id}/payments
Required scope: invoices:payments
Records a manual payment against one visible invoice and returns the created payment object with 201 Created. The API rechecks the invoice's current balance and prevents concurrent requests from applying against the same stale balance.
| Field | Type | Required | Description |
|---|---|---|---|
amount | number or numeric string | Yes | Payment amount with up to four decimal places. Use a positive amount for an invoice balance or a negative amount when applying a credit note. The amount cannot exceed the remaining signed balance. |
payment_date | string | Yes | Payment date in YYYY-MM-DD format. |
reference | string | No | Manual payment reference, up to 255 characters. |
A zero payment is accepted only for a zero-balance invoice when the account has no active payment-provider connection or payment-sync subscription, matching the SalesBinder manual-payment workflow.
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513/payments" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: invoice-1042-payment-001" \
--data '{
"amount": "50.00",
"payment_date": "2026-07-19",
"reference": "Bank transfer 8472"
}'{
"id": "2ce987a5-19a8-4bbe-ae2b-cff6da9fbfab",
"object": "payment",
"invoice_id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"amount": "50.0000",
"type": "payment",
"reference": "Bank transfer 8472",
"payment_date": "2026-07-19",
"card": null
}Use a unique Idempotency-Key for each intended payment. An identical retry during the short idempotency window returns the original 201 response with Idempotent-Replayed: true. Reusing the key with different request data returns 409 idempotency_key_reused. After the short window expires, the same request can create another payment when an eligible balance remains.
The endpoint records manual payments only. It does not charge a saved card, contact a payment provider, issue a refund against an earlier payment, or accept provider payment-method identifiers. Use the appropriate SalesBinder payment integration for provider-backed payments.
Payment access also requires the API key's user to retain the current invoice-list and apply-payments permissions. Account and assigned-user visibility are enforced before the write. A payment and the resulting invoice totals and status are committed together; if the invoice cannot be refreshed, no payment is retained.
Refund a manual payment
POST/api/v3/invoices/{invoice_id}/payments/{payment_id}/refunds
Required scope: invoices:refunds
Records a manual refund against one original manual payment and returns the linked refund object with 201 Created. The original payment remains in payment history, and the refund appears as a separate object with a negative amount and type set to refund.
| Field | Type | Required | Description |
|---|---|---|---|
amount | number or numeric string | Yes | Positive refund amount with no more than two decimal places. It cannot exceed the original payment's remaining refundable amount. |
refund_date | string | Yes | Refund date in YYYY-MM-DD format. |
reference | string | No | Manual refund reference, up to 255 characters. |
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513/payments/2ce987a5-19a8-4bbe-ae2b-cff6da9fbfab/refunds" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: invoice-1042-refund-001" \
--data '{
"amount": "10.00",
"refund_date": "2026-07-20",
"reference": "Returned goods"
}'{
"id": "fa81b6df-b21b-4546-a787-ea7d1089305d",
"object": "payment",
"invoice_id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"amount": "-10.0000",
"type": "refund",
"reference": "Returned goods",
"payment_date": "2026-07-20",
"card": null
}Each refund locks the invoice and original payment, then recalculates all linked refunds before saving. Concurrent requests therefore cannot both spend the same remaining refundable amount. The refund and resulting invoice totals and status are committed together.
Use a unique Idempotency-Key for each intended refund. An identical retry during the short idempotency window returns the original 201 response with Idempotent-Replayed: true instead of recording another refund.
This endpoint intentionally rejects provider-backed or card payments with 409 provider_refund_required. Refund those payments through the established SalesBinder payment integration so the external provider and local invoice remain coordinated. The API endpoint never calls a payment provider and never deletes or rewrites the original payment.
Refund access requires the current invoice-list and apply-payments permissions in addition to the dedicated API scope. The invoice and original payment must both belong to the current account, and the invoice must remain inside the user's assigned-invoice visibility boundary.
List invoice payments
GET/api/v3/invoices/{invoice_id}/payments
Required scope: invoices:read
Returns recorded payments and refunds for one visible invoice, ordered by payment date with the newest first. Positive amounts are payments and negative amounts are refunds.
| Parameter | Type | Required | Description |
|---|---|---|---|
page | integer | No | Page number. Defaults to 1. |
limit | integer | No | Records per page from 1 through 100. Defaults to 20. |
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513/payments?limit=20" \
-H "Authorization: Bearer sb_live_your_api_key" \
-H "Accept: application/json"{
"object": "list",
"url": "/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513/payments",
"has_more": false,
"data": [
{
"id": "2ce987a5-19a8-4bbe-ae2b-cff6da9fbfab",
"object": "payment",
"invoice_id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"amount": "50.0000",
"type": "payment",
"reference": "Card payment",
"payment_date": "2026-07-18",
"card": {
"brand": "visa",
"last4": "4242"
}
},
{
"id": "fa81b6df-b21b-4546-a787-ea7d1089305d",
"object": "payment",
"invoice_id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"amount": "-10.0000",
"type": "refund",
"reference": "Partial refund",
"payment_date": "2026-07-19",
"card": null
}
],
"pagination": {
"page": 1,
"per_page": 20,
"total_pages": 1,
"total_records": 2
}
}The response includes only the payment fields documented above.
Payment history follows the invoice's account and assigned-user visibility. It does not require payment-application permission because this endpoint cannot create, change, refund, or delete a payment.
Dispatch an invoice
POST/api/v3/invoices/{invoice_id}/dispatch
Required scope: invoices:dispatch
Marks an active invoice as dispatched by setting its date_sent. This action does not email the invoice or contact the customer. It requires the current user's invoice-modify permission and accepts unpaid, partially paid, and paid-in-full invoices.
The optional date_sent field must use YYYY-MM-DD format. When omitted, SalesBinder uses the current date in the account and user's configured timezone. If the invoice already has a dispatch date, the original date is preserved so repeating the action is safe.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513/dispatch" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: dispatch-invoice-c40e5d25" \
--data '{
"date_sent": "2026-07-20"
}'Example response
{
"id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"object": "invoice",
"invoice_number": 1002,
"status_id": 9,
"status": "Unpaid",
"date_sent": "2026-07-20",
"amount_paid": "0.0000",
"amount_due": "125.0000",
"lines": [
{
"id": "4fe2627c-6bb7-480c-9f46-b4558416f82c",
"object": "invoice_line",
"item_id": "4bb16375-9674-4e38-bab0-bcb15b97b76d",
"name": "Example Widget",
"quantity": "1.0000"
}
]
}The response is the complete invoice detail object. A cancelled invoice returns 409 invoice_dispatch_not_allowed. Send an Idempotency-Key to replay the original response for quick network retries; this is separate from the repeat-safe preservation of the first dispatch date.
Cancel an invoice
POST/api/v3/invoices/{invoice_id}/cancel
Required scope: invoices:cancel
Cancels an unpaid invoice without deleting its financial record or line items. The invoice must have no payment transactions, packing lists, shipping shipments, shipped quantity, or drop-shipping activity. Cancellation also requires the current user's invoice-modify permission.
If the invoice was created from a sales order, cancellation removes that invoice association and refreshes the sales order's invoiced quantities. This differs from invoice deletion, which refuses to remove an associated invoice.
The request body must be an empty JSON object. Arbitrary status or invoice fields are rejected.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513/cancel" \
--request POST \
--header "Authorization: Bearer YOUR_API_KEY" \
--header "Content-Type: application/json" \
--header "Idempotency-Key: cancel-invoice-c40e5d25" \
--data '{}'Example response
{
"id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"object": "invoice",
"invoice_number": 1002,
"status_id": 15,
"status": "Cancelled",
"amount_paid": "0.0000",
"amount_due": "125.0000",
"lines": [
{
"id": "4fe2627c-6bb7-480c-9f46-b4558416f82c",
"object": "invoice_line",
"item_id": "4bb16375-9674-4e38-bab0-bcb15b97b76d",
"name": "Example Widget",
"quantity": "1.0000"
}
]
}The response uses the complete invoice detail object with status 15. Repeating the action for an already-cancelled invoice returns its current cancelled representation. Send an Idempotency-Key to replay the original response for quick network retries.
Cancellation and sales-order unlinking are completed together. Inventory totals and unique-item sold status may update shortly after the response. SalesBinder returns 409 invoice_cancel_not_allowed when payment or fulfillment activity makes cancellation unsafe.
Delete an invoice
DELETE/api/v3/invoices/{invoice_id}
Required scope: invoices:delete
Deletes an eligible unpaid invoice and its lines. Deletion is limited to invoices with:
- no applied payments or transaction records;
- no sales-order or other document association;
- no packing list or shipping shipment;
- no shipped quantity; and
- no drop-shipping activity.
SalesBinder returns 409 invoice_delete_not_allowed when the invoice exists within the key's visibility boundary but does not meet every deletion condition. Deleting an invoice never deletes related payments, sales orders, packing lists, or shipments.
Example request
curl "https://yourbusiness.salesbinder.com/api/v3/invoices/c40e5d25-c573-48ec-aa46-9737eddf2513" \
--request DELETE \
--header "Authorization: Bearer YOUR_API_KEY"Example response
{
"id": "c40e5d25-c573-48ec-aa46-9737eddf2513",
"object": "invoice",
"deleted": true
}The invoice and its lines are deleted together. For inventory lines, on-hand quantities may update shortly after the response. Service-only invoices do not change inventory.
Permissions and write behavior
API key scopes can reduce access but cannot exceed the current user's SalesBinder permissions. The user must currently be able to list invoices. Without the current view-all-invoices permission, list and retrieve operations are limited to invoices assigned to that user.
Creating, updating, dispatching, or cancelling an invoice also requires the current invoice-modify permission. Deletion requires the current invoice-delete permission. If that permission is not configured, SalesBinder may use the invoice-modify permission; an explicit denial is always respected. Inventory selling-price overrides require the current modify-selling-prices permission, and location-limited users can only select inventory in their permitted location.
Updating is limited to the explicitly documented fields on eligible unpaid invoices. Dispatch, manual payments, manual refunds, and cancellation use dedicated endpoints and independent scopes; they cannot email a customer, charge saved cards, or issue provider refunds. Deletion is limited to unpaid invoices without payment, document associations, packing, shipping, or drop-shipping activity. API v3 does not support invoice email delivery, archiving, restoring, setting an arbitrary status, or changing fulfillment state. Unsupported fields and actions are rejected.