Base URL: https://couplrfsm.com/api/v1. Conventions shared by every endpoint (examples, ids, dates, money) are on the API reference page. Errors, pagination and idempotency are in Errors, limits and retries.
List invoices#
GET /api/v1/invoices · requires the invoices:read ability
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
page |
integer | No | Default: 1. |
per_page |
integer | No | Values above 100 are served as 100. Default: 25. |
updated_since |
string (date-time) | No | Only records changed at or after this time. ISO 8601, for example 2026-11-14T15:00:00Z. |
status |
string | No | Exact status match, e.g. paid. |
customer_id |
integer | No | |
created_from |
string (date) | No | |
created_to |
string (date) | No |
Example request
curl "https://couplrfsm.com/api/v1/invoices" \
-H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
"data": [
{
"id": "9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21",
"invoice_number": "1047",
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_id": 9312,
"status": "paid",
"amount": "389.00",
"notes": null,
"hosted_invoice_url": null,
"created_at": "2026-12-02T17:20:05+00:00",
"updated_at": "2026-12-02T18:01:44+00:00"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"last_page": 1
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
422 |
A parameter or field is invalid (validation_failed). errors maps each field to its messages. |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Create a draft invoice#
POST /api/v1/invoices · requires the invoices:write ability · accepts Idempotency-Key
Creates an invoice with status draft. Nothing is sent to the
customer and nothing is charged. The draft appears in Couplr, where
someone reviews it and sends it, or you send it with
POST /invoices/{id}/send. An invoice cannot be marked as paid or
charged through the API.
A line with price_book_item_id uses that price book item. A line
without one is matched to a price book item with the same name, or
added to the price book as a new item. A job can have one draft:
creating another for the same job replaces the first.
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key |
string | No | Makes a retry of this request safe. See "Retries and idempotency". |
Request body (application/json)
Fields not listed are ignored. The invoice is always created as a draft.
| Field | Type | Required | Description |
|---|---|---|---|
customer_id |
integer | Yes | |
job_id |
integer or null | No | A job of this customer to attach the invoice to. |
notes |
string or null | No | |
due_days |
integer or null | No | Payment terms in days. Omit to use the company default. |
line_items |
array of objects | Yes | |
line_items[].price_book_item_id |
integer or null | No | An existing price book item. When sent, name is not needed. |
line_items[].name |
string | No | Required without price_book_item_id. |
line_items[].description |
string or null | No | |
line_items[].quantity |
number | No | Default: 1. |
line_items[].unit_price |
number | No | Dollars. Required without price_book_item_id. With one, defaults to the price book price. |
Example request
curl -X POST "https://couplrfsm.com/api/v1/invoices" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: YOUR_UNIQUE_KEY" \
-d '{"customer_id":1842,"job_id":9312,"notes":"Replaced condenser fan motor.","line_items":[{"name":"Condenser fan motor","quantity":1,"unit_price":289},{"name":"Service call","quantity":1,"unit_price":100}]}'
Example response (201)
{
"data": {
"id": "9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21",
"invoice_number": "1047",
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_id": 9312,
"status": "paid",
"amount": "389.00",
"notes": null,
"hosted_invoice_url": null,
"created_at": "2026-12-02T17:20:05+00:00",
"updated_at": "2026-12-02T18:01:44+00:00"
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
422 |
A parameter or field is invalid (validation_failed). errors maps each field to its messages. |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Get an invoice#
GET /api/v1/invoices/{id} · requires the invoices:read ability
Includes line_items.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes |
Example request
curl "https://couplrfsm.com/api/v1/invoices/9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21" \
-H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
"data": {
"id": "9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21",
"invoice_number": "1047",
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_id": 9312,
"status": "paid",
"amount": "389.00",
"notes": null,
"hosted_invoice_url": null,
"created_at": "2026-12-02T17:20:05+00:00",
"updated_at": "2026-12-02T18:01:44+00:00"
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
404 |
No such record in this company (not_found). |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Send a draft invoice#
POST /api/v1/invoices/{id}/send · requires the invoices:send ability · accepts Idempotency-Key
Sends a draft invoice to the customer by email with Couplr's payment link, the same as "Send invoice" in the apps. The customer pays through that link. Nothing is charged by this call, and there is no way to record a payment made any other way.
A draft that was saved in Couplr as a bank-only or a financing invoice is sent that way, and a deposit already credited on the draft stays on it. You cannot choose how the customer pays or set a deposit.
There is no request body. The draft is sent as it stands: its
quantities, prices, notes and extra recipients are not changed. Each
line goes out under its price book item's current name, and sales tax
is worked out again from the account's current tax settings, as it is
whenever an invoice is sent from Couplr. Read amount in the
response for the amount billed.
The response has status processing while Couplr prepares the
payment link. A moment later the invoice becomes sent,
hosted_invoice_url is filled in and the invoice.sent event is
delivered.
Refused with 422 on invoice when: the invoice is not a draft; the
customer has no email address; online payments are not set up for the
account; or the draft was set up in Couplr with a payment option the
API does not send (a charge to a saved card, or split payments); a
line uses a price book item that has
been archived; or another send of the same invoice is in progress.
Send those from Couplr.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id |
string (uuid) | Yes |
Headers
| Name | Type | Required | Description |
|---|---|---|---|
Idempotency-Key |
string | No | Makes a retry of this request safe. See "Retries and idempotency". |
Example request
curl -X POST "https://couplrfsm.com/api/v1/invoices/9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21/send" \
-H "Authorization: Bearer YOUR_API_KEY"
Example response (200)
{
"data": {
"id": "9d3f6a52-0c1e-4c57-9d0a-3a0f8a4a7b21",
"invoice_number": "1047",
"customer_id": 1842,
"customer_name": "Dana Whitfield",
"job_id": 9312,
"status": "processing",
"amount": "389.00",
"notes": "Replaced condenser fan motor.",
"hosted_invoice_url": null,
"created_at": "2026-12-02T17:20:05+00:00",
"updated_at": "2026-12-02T18:01:44+00:00",
"line_items": [
{
"name": "Condenser fan motor",
"quantity": 1,
"rate": "289.00"
},
{
"name": "Service call",
"quantity": 1,
"rate": "100.00"
}
]
}
}
Errors
| Status | When |
|---|---|
401 |
No key (api_key_missing), the key is unknown or revoked (api_key_invalid), the key had an end date that has passed (api_key_expired), or the key belongs to a private trial sandbox whose access window has ended (sandbox_expired). |
403 |
The key lacks the ability this endpoint needs (ability_missing), no admin user is left to act for the key (no_acting_admin), or the company's account is not yet verified. |
404 |
No such record in this company (not_found). |
422 |
A parameter or field is invalid (validation_failed). errors maps each field to its messages. |
429 |
Too many requests (rate_limited). Wait Retry-After seconds. |
Invoice object#
| Field | Type | Description |
|---|---|---|
id |
string (uuid) | |
invoice_number |
string or null | |
customer_id |
integer or null | |
customer_name |
string or null | |
job_id |
integer or null | |
status |
string or null | |
amount |
string or null | Decimal string in dollars, e.g. "125.00". |
notes |
string or null | |
hosted_invoice_url |
string or null | The customer-facing payment page. Treat as a secret link. |
created_at |
string (date-time) or null | |
updated_at |
string (date-time) or null | |
line_items |
array of objects | On a single invoice only, not in lists. |
line_items[].name |
string or null | |
line_items[].quantity |
number or null | |
line_items[].rate |
string or null | Decimal string in dollars. |