Evyoo POS API v1

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.

needs invoices:read Sales

Endpoints#

List: GET/api/v1/invoices   One record: GET/api/v1/invoices/{id}

Example request#

List with a page size and a sort:

bash
curl "https://votre-entreprise.evyooht.com/api/v1/invoices?per_page=5&sort=-date" \
  -H "Authorization: Bearer evy_at_votre_jeton"
powershell
$headers = @{ Authorization = "Bearer evy_at_votre_jeton" }
Invoke-RestMethod -Uri "https://votre-entreprise.evyooht.com/api/v1/invoices?per_page=5&sort=-date" -Headers $headers
javascript
const 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);
php
$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);
python
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:

bash
curl "https://votre-entreprise.evyooht.com/api/v1/invoices/4149" \
  -H "Authorization: Bearer evy_at_votre_jeton"
powershell
$headers = @{ Authorization = "Bearer evy_at_votre_jeton" }
Invoke-RestMethod -Uri "https://votre-entreprise.evyooht.com/api/v1/invoices/4149" -Headers $headers
javascript
const 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);
php
$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);
python
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.

ParameterTypeDescription
pageintegerPage 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_pageintegerResults per page, from 1 to 100. Default: 25.
sortstringSort 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.
statusstringnew, open, hold, regular, void, or all. When omitted, drafts (status hold) are not listed. Allowed values: new, open, hold, regular, void, all.
payment_statusstringpaid or unpaid. Allowed values: paid, unpaid.
customer_idintegerOnly records of this customer.
store_idintegerOnly documents of this store.
currencystringOnly documents in this currency (USD or HTG).
date_fromstring (date)Only documents dated on or after this day (YYYY-MM-DD).
date_tostring (date)Only documents dated on or before this day (YYYY-MM-DD), the whole day included.
searchstringText contained in the invoice number, the customer name or the purchase order number.
updated_sincestringOnly 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.

FieldTypeDescription
idintegerUnique identifier. Use it in the detail route.
numberstring| nullHuman-readable document number, for example I1-4149.
store_idinteger| nullIdentifier of the store that owns the document (see the stores resource).
datestring(date-time, local) | nullDocument date and time (store local time, no time zone).
customer_idinteger| nullIdentifier of the customer (see the customers resource).
customer_namestring| nullFull name of the customer.
status"new"| "open" | "hold" | "regular" | "void" | nullnew, open, hold, regular or void.
payment_status"paid"| "unpaid" | nullpaid or unpaid.
payment_typestring| nullHow the document is paid, as recorded at sale time (for example Cash, Account).
currencystring| nullCurrency of the document: USD or HTG.
exchange_ratenumber| nullExchange rate between USD and HTG recorded on the document.
quantity_totalnumber| nullTotal quantity of items on the document.
items_totalnumber| nullSum of the item amounts, before discount, tax and shipping. The document totals are the reference: lines carry facts, not computed line totals.
taxnumber| nullTax amount.
discount_percentnumber| nullDiscount, as a percentage.
discount_amountnumber| nullDiscount amount.
shippingnumber| nullShipping and transport charges.
totalnumber| nullGrand total of the document. Zero when the document is void.
amount_paidnumber| nullAmount already paid on the document.
depositnumber| nullDeposit paid.
cost_total needs costs:readnumber| nullCost of goods sold. Requires costs:read.
po_numberstring| nullCustomer purchase order number, when recorded.
quote_numberstring| nullNumber of the quote this invoice comes from, when there is one.
sales_order_numberstring| nullNumber of the sales order this invoice comes from, when there is one.
notesstring| nullFree-text notes printed on the document.
created_atstring(date-time, local) | nullWhen the record was created (local time, no time zone).
updated_atstring(date-time, local) | nullWhen 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.

FieldTypeDescription
idintegerIdentifier of the line.
product_idinteger| nullIdentifier of the product. 0 for a free-text line.
namestring| nullItem name as printed on the document.
descriptionstring| nullItem description as printed on the document.
typestring| nullKind of item: Inventory, Service or Special.
quantitynumber| nullQuantity sold, in the unit shown in unit.
unitstring| nullUnit of the line (for example Box of 100).
unit_pricenumber| nullPrice of one unit. Zero when the invoice is void.
base_quantitynumber| nullQuantity expressed in the base unit of the product.
base_unit_pricenumber| nullPrice of one base unit. Zero when the invoice is void.
cost needs costs:readnumber| nullCost 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.

FieldTypeDescription
datestring(date-time, local) | nullDate and time of the payment.
cashnumber| nullAmount paid in cash.
cardnumber| nullAmount paid by debit or credit card.
chequenumber| nullAmount paid by cheque.
cheque_numberstring| nullCheque number.
accountnumber| nullAmount charged to the customer account.
depositnumber| nullDeposit applied.
currencystring| nullCurrency of the payment.
exchange_ratenumber| nullExchange rate recorded on the payment.

Example response: list#

json
{
  "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#

json
{
  "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.

StatusWhen
400A query parameter is invalid or unknown. Every fault is reported at once in error.details. Nothing is ignored silently.
401The token is missing, malformed, expired or revoked (missing_token or invalid_token). Ask for a new token.
403Your token does not carry the permission this route needs (insufficient_scope), or the request was not made over HTTPS (https_required).
429Too many requests this minute. Wait for the number of seconds in the Retry-After header.