Keep a synchronised copy of purchase invoices, purchase delivery notes and sales invoices. Each call returns what has been created, updated and deleted since the previous one.
GET /integration/purchases/invoices/changes
GET /integration/purchases/deliveries/changes
GET /integration/sales/invoices/changes
If you need to fetch new documents and mark them as processed, use Retrieving data for billing systems instead.
Before you start
Base URL: https://app.tspoonlab.com/recipes/api
Headers
rememberme· required — Session token returned by the login.order· optional — Cost center id (Cost centers). Defaults to the user's active cost center.
Login — Returns the token as plain text.
curl https://app.tspoonlab.com/recipes/api/login \
-d [email protected] \
-d password=XXXXXXX
Permissions — The purchase endpoints require permission to view purchase orders; the sales endpoint, permission to view sales.
Dates — Returned as milliseconds since 1970 (epoch).
Responses may include fields other than the documented ones. Use only the documented fields.
How sync works
First call without
cursor: returns every document ininserts. To start from a given day, sendchangedSince.While
hasMoreistrue, call again with thecursoryou received.Store the last
cursor. On the next sync, call with it: you will only receive what has changed.
Store a separate cursor for each endpoint.
Common parameters
cursorstring · optional — Cursor from the previous call. When sent,changedSinceand$filterare ignored.changedSincedate · optional — Changes since this day, asYYYY-MM-DD. Cannot be later than today.$filterstring · optional — Filter on each endpoint's fields (see Filter). It is stored in the cursor: send it only on the first call.rowsinteger · optional — Changes per page, from 1 to 100. Defaults to 100.includeInternalboolean · optional —falseexcludes internal vendors or customers. Defaults totrue.
includeInternal, onlyValidated, idVendor and idCustomer are not stored in the cursor: send them with the same value on every call.
Response
{
"inserts": [ … ],
"updates": [ … ],
"deletes": [
{ "id": "3515834441676562996102020009", "deletedAt": 1767268800000 }
],
"cursor": "MjAyNi0wMS0wMSAxMjowMDowMC4wfDM1MTU4MzQ0NDE2NzY1NjI5OTYxMDIwMjAwMDk",
"hasMore": false
}insertsarray — Documents created since the cursor. On the first load, all of them.updatesarray — Documents created before and updated after. Each document appears once, in its current state.deletesarray — Deleted documents:idstring anddeletedAtdate.cursorstring — For the next call.nullif the first load returns nothing.hasMoreboolean —trueif more changes are available.
Good to know
Changes from the last 5 minutes arrive on the next call.
deletesis not filtered: ignore anyidyou don't have.A document that stops matching the filter does not appear in
deletes.The same
idcan appear in bothupdatesanddeleteson one page: apply the most recent one by comparingupdatedAtanddeletedAt.Changes to vendor or customer data (name, tax id, accounts…) do not mark their documents as updated.
Filter
OData syntax: eq, ne, gt, ge, lt, le, in, and, or, not (…), parentheses, year(), month() and contains().
Dates:
YYYY-MM-DDwithout quotes. All operators allowed.Ids: number without quotes. Only
eq,neandin.Text: in single quotes. Only
eq,ne,inandcontains(). Case- and accent-sensitive.
curl -G https://app.tspoonlab.com/recipes/api/integration/purchases/invoices/changes \
-H "rememberme: $TOKEN" \
--data-urlencode '$filter=year(date) eq 2026 and idVendor in (3515834441676562996102020004, 3515834441676562996102020005)'
Errors — An invalid cursor, changedSince or $filter, or rows out of range, returns 400 with code, message and params.
Purchase invoices
GET /integration/purchases/invoices/changes
Query parameters — The common ones, plus:
onlyValidatedboolean · optional —truereturns only validated invoices. Defaults tofalse.idVendorstring · optional — Only invoices from this vendor.
$filter fields: date, dateAccounting (date), idVendor (id), invoiceNum, documentNum (text).
Example
curl "https://app.tspoonlab.com/recipes/api/integration/purchases/invoices/changes?changedSince=2026-01-01" \
-H "rememberme: $TOKEN"
Response — Each invoice in inserts and updates:
{
"id": "3515834441676562996102020001",
"invoiceNum": "F-2026-0042",
"documentNum": "000123",
"date": 1767225600000,
"dateAccounting": null,
"dateDue": 1769904000000,
"createdAt": 1767268800000,
"updatedAt": 1767268800000,
"idVendor": "3515834441676562996102020004",
"vendor": "García Distribution",
"codeVendor": "P001",
"accountVendor": "40000001",
"nif": "B12345678",
"inEuropeanUnion": false,
"inVies": false,
"country": "ES",
"paid": false,
"validated": true,
"locked": false,
"comment": null,
"codePaymentType": "TRANSF",
"base": 100.0,
"taxes": 10.0,
"total": 110.0,
"listTaxes": [
{ "id": "3515834441676562996102020006", "type": 0, "base": 100.0, "percent": 10.0, "total": 10.0 }
],
"listCostTypeTaxes": [ … ],
"listDeliveries": [ … ]
}idstring — Invoice id.invoiceNumstring — Vendor's invoice number.documentNumstring — Internal document number.date,dateAccounting,dateDuedate — Invoice date, accounting date (ifnull, usedate) and due date.createdAt,updatedAtdate — Created and last updated.idVendor,vendor,codeVendor,accountVendor,nifstring — Vendor: id, name, code, ledger account and tax id.inEuropeanUnion,inViesboolean — Intra-EU vendor and registered in VIES.countrystring — Vendor's country.paid,validated,lockedboolean — Paid, validated and locked.commentstring — Comment.codePaymentTypestring — Payment method code.idCostTypeVendor,costTypeVendor,codeCostTypeVendor,accountCostTypeVendor,accountAuxCostTypeVendorstring — Vendor's default cost account: id, name, code, ledger account and auxiliary account.idBusinessLine,businessLine,codeBusinessLinestring — Business line.idDocument,extDocumentstring — Attached document: id and extension.base,taxes,totalnumber — Tax base, taxes and total.totalincludes withholding.listTaxesarray — Taxes:id,type,base,percentandtotal.type:0VAT ·1shipping ·2discount ·3other ·4withholding.listCostTypeTaxesarray — VAT by cost account, calculated from received lines: accountidanddescr(nullif the lines have none) andlistTaxes(type,base,percent,total).listDeliveriesarray — The invoice's delivery notes, with the fields in Purchase delivery notes (withoutcreatedAtorupdatedAt).
Purchase delivery notes
Received delivery notes only.
GET /integration/purchases/deliveries/changes
Query parameters — The common ones, plus:
idVendorstring · optional — Only delivery notes from this vendor.
$filter fields: date, dateSent (date), idVendor (id), deliveryNum, deliveryFor (text).
Example
curl "https://app.tspoonlab.com/recipes/api/integration/purchases/deliveries/changes?changedSince=2026-01-01" \
-H "rememberme: $TOKEN"
Response — Each delivery note in inserts and updates:
{
"id": "3515834441676562996102020002",
"deliveryNum": "A-7781",
"deliveryFor": "PO-0153",
"date": 1767225600000,
"dateFormatted": "2026/01/01",
"dateSent": 1767139200000,
"dateSentFormatted": "2025/12/31",
"createdAt": 1767268800000,
"updatedAt": 1767268800000,
"idVendor": "3515834441676562996102020004",
"vendor": "García Distribution",
"locked": false,
"baseCalculated": 100.0,
"base": 100.0,
"taxes": 10.0,
"total": 110.0,
"listTaxes": [ … ],
"listDeliveries": [
{
"id": "3515834441676562996102020007",
"position": 0,
"idComponent": "3515834441676562996102020008",
"component": "Plum tomato",
"quantity": 20.0,
"unit": "kg",
"cost": 5.0,
"hasFormat": true,
"quantityFormat": 4.0,
"unitFormat": "5 kg box",
"costFormat": 25.0,
"iva": 10.0
}
],
"listSent": [ … ]
}idstring — Delivery note id.deliveryNumstring — Delivery note number.deliveryForstring — Delivery note reference, usually the order number.datedate — Received date; if none, the sent date.dateFormattedstring — The same, asYYYY/MM/DD.dateSentdate — Order sent date.dateSentFormattedstring — The same, asYYYY/MM/DD.createdAt,updatedAtdate — Created and last updated.idVendor,vendor,codeVendor,accountVendor,nifstring — Vendor: id, name, code, ledger account and tax id.vendorType,vendorTypeCodestring,vendorTypeInternalboolean — Vendor type: name, code and whether it is internal.lockedboolean — Locked.sentBy,receivedBystring — Who placed the order and who received it.idCostType,costType,codeCostType,accountCostType,accountAuxCostTypestring — Delivery note's cost account. When assigned per line, it is on each line.idBusinessLine,businessLine,codeBusinessLinestring — Business line.baseCalculatednumber — Base calculated from received lines, with 5 decimals.base,taxes,totalnumber — Base, taxes (including shipping, discounts and other) and total.listTaxesarray — Taxes:id,type,base,percentandtotal.type:0VAT ·1shipping ·2discount ·3other.listDeliveriesarray — Received lines.listSentarray — Lines of the order as sent.
Each received line (listDeliveries):
idstring — Line id.positioninteger — Order.idComponent,component,codeComponentstring — Product: id, name and code.codeVendorComponentstring — Vendor's product code.commentstring — Comment.quantitynumber,idUnit,unitstring — Quantity in the product's base unit.costnumber — Cost per base unit. Line amount:quantity×cost.hasFormatboolean — Whether it was bought in a format (e.g. boxes).quantityFormatnumber,idUnitFormat,unitFormatstring,costFormatnumber — Format: quantity, unit and price per format.nullifhasFormatisfalse.idStore,storestring — Store.ivanumber — VAT %.idCostType,costType,codeCostType,accountCostType,accountAuxCostTypestring — Line's cost account.idBusinessLine,businessLine,codeBusinessLinestring — Line's business line.listTypesarray — Product families:idanddescr.recibidoboolean — Alwaystrue.
Each line of the order as sent (listSent): the same product, comment and format fields as a received line, with quantity, idUnit and unit in the purchase unit and cost as the purchase price.
Sales invoices
GET /integration/sales/invoices/changes
Query parameters — The common ones, plus:
idCustomerstring · optional — Only invoices for this customer.
$filter fields: date, dateAccounting, dateDue (date), idCustomer (id), invoiceNum, documentNum (text).
Example
curl "https://app.tspoonlab.com/recipes/api/integration/sales/invoices/changes?changedSince=2026-01-01" \
-H "rememberme: $TOKEN"
Response — Each invoice in inserts and updates:
{
"id": "3515834441676562996102020003",
"invoiceNum": "V-2026-0010",
"documentNum": "000045",
"date": 1767225600000,
"dateAccounting": null,
"dateDue": 1769904000000,
"createdAt": 1767268800000,
"updatedAt": 1767268800000,
"idCustomer": "3515834441676562996102020010",
"customer": "Hotel Mediterráneo",
"codeCustomer": "C015",
"accountCustomer": "43000015",
"nif": "A87654321",
"paid": false,
"locked": false,
"base": 500.0,
"taxes": 50.0,
"total": 550.0,
"listTaxes": [ … ],
"listCostTypeTaxes": [ … ],
"listDeliveries": [ … ]
}idstring — Invoice id.invoiceNumstring — Invoice number.documentNumstring — Document number.date,dateAccounting,dateDuedate — Invoice date, accounting date (ifnull, usedate) and due date.createdAt,updatedAtdate — Created and last updated.idCustomer,customer,codeCustomer,accountCustomer,nifstring — Customer: id, name, code, ledger account and tax id.paid,lockedboolean — Paid and locked.commentstring — Comment.codePaymentTypestring — Payment method code.idCostTypeVendor,costTypeVendor,codeCostTypeVendor,accountCostTypeVendor,accountAuxCostTypeVendorstring — Customer's default cost account: id, name, code, ledger account and auxiliary account.idDocument,extDocumentstring — Attached document: id and extension.base,taxes,totalnumber — Tax base, taxes and total.listTaxesarray — Taxes:id,type,base,percentandtotal.type:0VAT ·1shipping ·2discount ·3other.listCostTypeTaxesarray — VAT by cost account, calculated from sent lines: accountidanddescr(nullif the lines have none) andlistTaxes(type,base,percent,total).listDeliveriesarray — The invoice's sales delivery notes.
Each sales delivery note (listDeliveries):
idstring — Delivery note id.invoiceNumstring — Delivery note number.datedate — Delivery note date.idCustomer,customer,customerCode,nifstring — Customer: id, name, code and tax id.address,cp,citystring — Customer's address, postcode and city.contact,phone,contactAux,phoneAux,mail,mailAux,mailCC,webstring — Customer contacts.customerType,customerTypeCodestring,customerTypeInternalboolean — Customer type: name, code and whether it is internal.basenumber — Base of the sent lines.listLines,listLinesPendingarray — Sent lines and lines pending shipment.
Each line (listLines, listLinesPending):
idstring — Line id.positioninteger — Order within the list, from 0.idComponent,component,codeComponentstring — Product sold.idMenu,menu,codeMenustring — Menu sold.codeCustomerProductstring — Customer's sales code for the product.idCustomerGroup,customerGroupstring — Product group.commentstring — Comment. On lines without product or menu, the sales product name.sentboolean — Sent.quantitynumber,idUnit,unitstring — Quantity and unit.costnumber — Unit sale price excluding VAT.costRecipenumber — Unit recipe cost.ivanumber — VAT %.listTypesarray — Product families:idanddescr.
Need help? Message us from the support chat in the bottom-right corner.
