Book a vendor bill
This recipe books a supplier’s bill into accounts payable. It is the most common integration: an expense tool, a procurement system or a script sending bills to neoo.
The example is a Swisscom phone bill for CHF 120.00 plus 8.1% VAT, due at the end of the month. It uses the account numbers of the standard neoo Swiss chart of accounts. Yours may differ, and step 2 shows how to look them up.
You need: an API key whose user’s role includes Vendors → Postings → Vendor Transaction. See Getting started.
1. Identify the vendor
Every bill needs a vendor that already exists in neoo. If you store the neoo vendor number in your own system, skip the lookup and send vendornumber in step 3.
Otherwise, search by name:
curl "https://apineo.z83.ch/client/acme/arap/vendor?name=swisscom" \
-H "X-API-Key: ak_your_key_here"
[
{
"id": 1001,
"name": "Swisscom (Schweiz) AG",
"vendornumber": "V-1042",
"city": "Bern",
"country": "CH"
}
]
No match? Create the vendor with POST /arap/vendor. The street name goes in address1 and the house number in street: Swiss payment files need them separately.
2. Look up accounts and tax
A bill line needs two account numbers:
- the expense account the cost is booked to, here
6510Telecommunications - the tax account for the VAT, here
11700Input VAT 8.1%
The bill as a whole also needs the accounts payable account (recordAccount), here 2000 Trade accounts payable.
Get the chart once and cache it. Accounts usable on vendor bills carry AP_amount in their link, and payable accounts carry AP:
curl https://apineo.z83.ch/client/acme/system/chart/accounts \
-H "X-API-Key: ak_your_key_here"
For tax rates and their accounts:
curl https://apineo.z83.ch/client/acme/system/taxes \
-H "X-API-Key: ak_your_key_here"
3. Book the bill
Send the bill to POST /arap/transaction/vendor. Leave out pending, and it is saved as a draft for someone to review in the app:
curl -X POST https://apineo.z83.ch/client/acme/arap/transaction/vendor \
-H "X-API-Key: ak_your_key_here" \
-H "Content-Type: application/json" \
-d @bill.json
{
"type": "transaction",
"vendor_id": 1001,
"documentNumber": "SC-2026-448812",
"invDate": "2026-09-01",
"dueDate": "2026-09-30",
"curr": "CHF",
"recordAccount": "2000",
"description": "Mobile subscription September",
"lines": [
{
"account": "6510",
"description": "Business mobile, 4 lines",
"amount": 120.00,
"taxAccount": "11700"
}
]
}
The response is the new transaction’s id:
{ "id": 15659 }
A few things to note:
documentNumberis the vendor’s own invoice number. Always send it: it is searchable in the app and lets you find the bill again (see step 5).invNumberis neoo’s own document number. Leave it out and neoo takes the next one from the company’s number sequence.- Tax is calculated from
taxAccount: 8.1% of 120.00 = 9.72, so the bill totals 129.72. If the vendor’s bill shows a slightly different tax because of rounding, send their figure astaxAmounton the line. - Amounts are net unless you send
"taxincluded": true. With it,amountis the gross amount and the tax is taken out of it. - Currency is
curr. For a foreign-currency bill, also sendexchangerate.
Attach the PDF
Add the original bill in the same request, so reviewers see it next to the entry. Send it as a base64 data URI in files:
{
"type": "transaction",
"vendor_id": 1001,
"…": "…",
"files": [
{ "name": "swisscom-2026-09.pdf", "data": "data:application/pdf;base64,JVBERi0xLjcK…" }
]
}
On the command line, base64 -w0 swisscom-2026-09.pdf produces the part after base64,. If you prefer not to base64-encode, send the request as multipart/form-data with one files part per file.
4. Approve: now or later
Later (recommended). The draft appears on a workstation in the app. A person checks it against the PDF and approves it. Your integration doesn’t need to do anything else.
Now. If the integration itself is trusted to post, add "pending": "0" to the request in step 3. The bill is posted straight away, subject to the company’s approval rules: if the user behind your key may only approve up to a certain amount, a larger bill is refused with amount_exceeded.
Approve an existing draft. Send the complete transaction again, with "pending": "0", to the approve endpoint:
curl -X POST https://apineo.z83.ch/client/acme/arap/transaction/vendor/15659/approve \
-H "X-API-Key: ak_your_key_here" \
-H "Content-Type: application/json" \
-d @bill-approved.json
The approve endpoint saves the body you send before posting it. Send the full transaction, not just the id, and include
"pending": "0".
5. Check the result
Read the transaction back to see what was booked, including the calculated tax and the attached files:
curl https://apineo.z83.ch/client/acme/arap/transaction/vendor/15659 \
-H "X-API-Key: ak_your_key_here"
To find bills by the vendor’s number instead of by id:
curl "https://apineo.z83.ch/client/acme/arap/transactions/vendor?document_number=SC-2026-448812" \
-H "X-API-Key: ak_your_key_here"
Pay it
To have neoo include the bill in the next bank payment file, send "payment_file": 1 and the vendor’s bank account as vc_bank_id when you book it. The Bank Payments endpoints in the reference cover the rest of the flow.
When it fails
| You get | Because | Fix |
|---|---|---|
400 vc_not_found |
vendornumber matched no vendor |
Look the vendor up, or create it (step 1). |
400 about curr |
Currency isn’t three letters, or you sent currency |
Send "curr": "CHF". |
422 closed_period |
invDate is in a closed period |
Ask the accountant, or use a date after the close. |
400 amount_exceeded |
You approved a bill above the user’s limit | Send it as a draft instead. |
The full list is on Errors.