Invoices
List invoices, their lines and payments
Sales invoices. Recent and archived invoices are returned together as one collection: totals, sorting and pagination cover both.
Statuses: new, open, hold (draft, hidden by default), regular (final), void. A void invoice keeps its identity (number, date, customer) but all its amounts are zero, lines and payments included, so that adding up a list never counts a cancelled sale. Quantities are kept.
Payments received on an invoice later, from the customer account, are in the payments resource.
Endpoints#
List: GET/api/v1/invoices One record: GET/api/v1/invoices/{id}
Example request#
List with a page size and a sort:
curl "https://votre-entreprise.evyooht.com/api/v1/invoices?per_page=5&sort=-date" \
-H "Authorization: Bearer evy_at_votre_jeton"$headers = @{ Authorization = "Bearer evy_at_votre_jeton" }
Invoke-RestMethod -Uri "https://votre-entreprise.evyooht.com/api/v1/invoices?per_page=5&sort=-date" -Headers $headersconst response = await fetch("https://votre-entreprise.evyooht.com/api/v1/invoices?per_page=5&sort=-date", {
headers: { Authorization: "Bearer evy_at_votre_jeton" },
});
const data = await response.json();
console.log(data);$ch = curl_init("https://votre-entreprise.evyooht.com/api/v1/invoices?per_page=5&sort=-date");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer evy_at_votre_jeton"],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($data);import requests
response = requests.get(
"https://votre-entreprise.evyooht.com/api/v1/invoices",
params={"per_page": 5, "sort": "-date"},
headers={"Authorization": "Bearer evy_at_votre_jeton"},
)
print(response.json())One record by its identifier:
curl "https://votre-entreprise.evyooht.com/api/v1/invoices/4149" \
-H "Authorization: Bearer evy_at_votre_jeton"$headers = @{ Authorization = "Bearer evy_at_votre_jeton" }
Invoke-RestMethod -Uri "https://votre-entreprise.evyooht.com/api/v1/invoices/4149" -Headers $headersconst response = await fetch("https://votre-entreprise.evyooht.com/api/v1/invoices/4149", {
headers: { Authorization: "Bearer evy_at_votre_jeton" },
});
const data = await response.json();
console.log(data);$ch = curl_init("https://votre-entreprise.evyooht.com/api/v1/invoices/4149");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer evy_at_votre_jeton"],
]);
$data = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($data);import requests
response = requests.get(
"https://votre-entreprise.evyooht.com/api/v1/invoices/4149",
headers={"Authorization": "Bearer evy_at_votre_jeton"},
)
print(response.json())Query parameters of the list#
All filters can be combined: they add up (AND). An unknown parameter or an invalid value is refused with a 400 error, never ignored.
| Parameter | Type | Description |
|---|---|---|
page | integer | Page number, starting at 1. A page beyond the data is empty, not an error. At most 10000 pages: filter instead of paging deeper. Default: 1. |
per_page | integer | Results per page, from 1 to 100. Default: 25. |
sort | string | Sort fields, separated by commas, with - in front for descending order. Up to 3 fields. Sortable fields: id, date, total, updated_at. Default: -date. Default: -date. |
status | string | new, open, hold, regular, void, or all. When omitted, drafts (status hold) are not listed. Allowed values: new, open, hold, regular, void, all. |
payment_status | string | paid or unpaid. Allowed values: paid, unpaid. |
customer_id | integer | Only records of this customer. |
store_id | integer | Only documents of this store. |
currency | string | Only documents in this currency (USD or HTG). |
date_from | string (date) | Only documents dated on or after this day (YYYY-MM-DD). |
date_to | string (date) | Only documents dated on or before this day (YYYY-MM-DD), the whole day included. |
search | string | Text contained in the invoice number, the customer name or the purchase order number. |
updated_since | string | Only records modified since this date (YYYY-MM-DD) or date and time (YYYY-MM-DDTHH:MM:SS). |
Response fields#
The list and the detail route return these fields. A field is null when the value is not recorded. A field marked needs permission is absent (not empty) unless your client holds that permission.
| Field | Type | Description |
|---|---|---|
id | integer | Unique identifier. Use it in the detail route. |
number | string| null | Human-readable document number, for example I1-4149. |
store_id | integer| null | Identifier of the store that owns the document (see the stores resource). |
date | string(date-time, local) | null | Document date and time (store local time, no time zone). |
customer_id | integer| null | Identifier of the customer (see the customers resource). |
customer_name | string| null | Full name of the customer. |
status | "new"| "open" | "hold" | "regular" | "void" | null | new, open, hold, regular or void. |
payment_status | "paid"| "unpaid" | null | paid or unpaid. |
payment_type | string| null | How the document is paid, as recorded at sale time (for example Cash, Account). |
currency | string| null | Currency of the document: USD or HTG. |
exchange_rate | number| null | Exchange rate between USD and HTG recorded on the document. |
quantity_total | number| null | Total quantity of items on the document. |
items_total | number| null | Sum of the item amounts, before discount, tax and shipping. The document totals are the reference: lines carry facts, not computed line totals. |
tax | number| null | Tax amount. |
discount_percent | number| null | Discount, as a percentage. |
discount_amount | number| null | Discount amount. |
shipping | number| null | Shipping and transport charges. |
total | number| null | Grand total of the document. Zero when the document is void. |
amount_paid | number| null | Amount already paid on the document. |
deposit | number| null | Deposit paid. |
cost_total needs costs:read | number| null | Cost of goods sold. Requires costs:read. |
po_number | string| null | Customer purchase order number, when recorded. |
quote_number | string| null | Number of the quote this invoice comes from, when there is one. |
sales_order_number | string| null | Number of the sales order this invoice comes from, when there is one. |
notes | string| null | Free-text notes printed on the document. |
created_at | string(date-time, local) | null | When the record was created (local time, no time zone). |
updated_at | string(date-time, local) | null | When the record was last modified (local time, no time zone). Use it with the updated_since filter to synchronize. |
Relation: lines#
Returned by the detail route only. The lines of the invoice.
| Field | Type | Description |
|---|---|---|
id | integer | Identifier of the line. |
product_id | integer| null | Identifier of the product. 0 for a free-text line. |
name | string| null | Item name as printed on the document. |
description | string| null | Item description as printed on the document. |
type | string| null | Kind of item: Inventory, Service or Special. |
quantity | number| null | Quantity sold, in the unit shown in unit. |
unit | string| null | Unit of the line (for example Box of 100). |
unit_price | number| null | Price of one unit. Zero when the invoice is void. |
base_quantity | number| null | Quantity expressed in the base unit of the product. |
base_unit_price | number| null | Price of one base unit. Zero when the invoice is void. |
cost needs costs:read | number| null | Cost of the line. Requires costs:read. Zero when the invoice is void. |
Relation: payments#
Returned by the detail route only. How the invoice was paid at the counter.
| Field | Type | Description |
|---|---|---|
date | string(date-time, local) | null | Date and time of the payment. |
cash | number| null | Amount paid in cash. |
card | number| null | Amount paid by debit or credit card. |
cheque | number| null | Amount paid by cheque. |
cheque_number | string| null | Cheque number. |
account | number| null | Amount charged to the customer account. |
deposit | number| null | Deposit applied. |
currency | string| null | Currency of the payment. |
exchange_rate | number| null | Exchange rate recorded on the payment. |
Example response: list#
{
"data": [
{
"id": 4149,
"number": "I1-4149",
"store_id": 1,
"date": "2026-03-15T14:30:00",
"customer_id": 58,
"customer_name": "Marie Dupont",
"status": "new",
"payment_status": "paid",
"payment_type": "Cash",
"currency": "USD",
"exchange_rate": 130.5,
"quantity_total": 12,
"items_total": 1250,
"tax": 0,
"discount_percent": 0,
"discount_amount": 0,
"shipping": 0,
"total": 1250,
"amount_paid": 1250,
"deposit": 0,
"cost_total": 900,
"po_number": "PO-7781",
"quote_number": "Q1-1087",
"sales_order_number": "S1-312",
"notes": "Delivered on Friday.",
"created_at": "2026-03-15T14:30:00",
"updated_at": "2026-03-15T14:30:00"
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 1,
"total_pages": 1
}
}Example response: one record#
{
"data": {
"id": 4149,
"number": "I1-4149",
"store_id": 1,
"date": "2026-03-15T14:30:00",
"customer_id": 58,
"customer_name": "Marie Dupont",
"status": "new",
"payment_status": "paid",
"payment_type": "Cash",
"currency": "USD",
"exchange_rate": 130.5,
"quantity_total": 12,
"items_total": 1250,
"tax": 0,
"discount_percent": 0,
"discount_amount": 0,
"shipping": 0,
"total": 1250,
"amount_paid": 1250,
"deposit": 0,
"cost_total": 900,
"po_number": "PO-7781",
"quote_number": "Q1-1087",
"sales_order_number": "S1-312",
"notes": "Delivered on Friday.",
"created_at": "2026-03-15T14:30:00",
"updated_at": "2026-03-15T14:30:00",
"lines": [
{
"id": 9001,
"product_id": 463,
"name": "Thermal paper roll 57x18m",
"description": "Thermal paper roll for receipt printers",
"type": "Inventory",
"quantity": 10,
"unit": "Box of 100",
"unit_price": 125,
"base_quantity": 1000,
"base_unit_price": 1.25,
"cost": 90
}
],
"payments": [
{
"date": "2026-03-15T14:30:00",
"cash": 1250,
"card": 0,
"cheque": 0,
"cheque_number": "",
"account": 0,
"deposit": 0,
"currency": "USD",
"exchange_rate": 130.5
}
]
}
}Errors#
The error format and the full list of codes are described in Errors.
| Status | When |
|---|---|
400 | A query parameter is invalid or unknown. Every fault is reported at once in error.details. Nothing is ignored silently. |
401 | The token is missing, malformed, expired or revoked (missing_token or invalid_token). Ask for a new token. |
403 | Your token does not carry the permission this route needs (insufficient_scope), or the request was not made over HTTPS (https_required). |
429 | Too many requests this minute. Wait for the number of seconds in the Retry-After header. |