Accounts Payable
When a supplier sends you an invoice or credit note over the network, GoRoute delivers it to your accounting system as a draft bill, exactly as the supplier sent it, with the supplier's PDF and the original XML attached. Your accountant takes it from there. If your bill was delivered into Odoo before 21 September 2026, read the caution below first โ those two attachments may not open.
GoRoute is the mailman, not the accountant. It makes no accounting decisions: it chooses no account, applies no tax, creates no contacts, and never posts, validates or pays anything.
What arrives in Odooโ
The quickest test is to click the attached PDF on the draft bill. If it opens as an invoice, none of this applies to you. If it opens as a wall of unreadable characters, it is affected, and the rest of this box tells you what happened and where to get the real file.
What went wrong. Between 8 August and 21 September 2026, every file GoRoute attached to a draft bill in Odoo 18 or earlier was stored as the file's own base64 text rather than as the file. Both attachments are present and neither opens โ a 27,900-byte PDF arrives as a 37,200-byte text file. Odoo 19 was never affected.
And the note could be bare. Over the same period, if GoRoute signs in to your Odoo as a user
without Administration / Settings rights โ which is the sensible setting for an integration user โ
the bill's note kept only its summary line, Peppol invoice received: INV-7, and lost the
supplier's name, VAT number, Peppol ID, address and stated totals. The two faults compound: when
the vendor could not be matched automatically and the note is bare, the only record of who the
supplier is was inside the attached files, which are the files that do not open.
Both are fixed, for new deliveries. The product fix for each shipped on 21 September 2026 and reached the production service the same day. Bills delivered after that carry openable files and a note that names the supplier whatever rights the Odoo user has.
Bills already delivered are not repaired. Redelivering the document with
POST /api/v1/inbound-documents/{id}/redeliver will not replace an attachment or rewrite a
note that GoRoute has already recorded as delivered. That is the "Delivered once" rule below
working as designed, and it means an affected bill stays affected.
How to get the correct file. Fetch it from GoRoute instead of from Odoo, with
GET /api/v1/inbound-documents/{id}/files/{kind} โ see API below. Those bytes are served
straight from the stored document and never passed through the Odoo connector, so the PDF and the
XML you download there are correct, and the supplier's identity is in them. You can then attach the
downloaded file to the bill yourself.
Where the supplier's details are and are not. The bill's own Internal Notes field carries the supplier's stated totals, the reason the vendor was left blank, and the GoRoute document id โ but it has never carried the supplier's name, VAT number, Peppol ID or address. Do not rely on it to identify the supplier.
The Odoo 18 and Odoo 19 behaviour above was measured against a real Odoo 18.0 and a real saas~19.4 by the engineer who wrote the fix, and is recorded with it. It is not our own measurement and this page does not present it as one.
For every received invoice, one draft vendor bill (a draft refund for a credit note):
| On the bill | Where it comes from |
|---|---|
| Bill reference, bill date, due date, currency | the supplier's invoice |
| Each line's description, quantity and unit price | the supplier's invoice, as stated |
| Document-level charges and allowances | their own lines |
| Account on each line | your Purchases journal's default account โ GoRoute sets none |
| Taxes on each line | none โ see below |
| Vendor | your contact with the same Peppol ID or VAT, if there is exactly one |
| Payment reference | the reference the supplier asks you to quote when you pay, into Odoo's Payment Reference field (payment_reference), and also into the note |
| Your purchase order | your own PO number, where the supplier quoted it, into Odoo's Source Document field (invoice_origin) โ and repeated in the note, because Odoo 18 and 19 do not show that field on a vendor bill |
| Supplier's payment details | in the note: how they ask to be paid, their bank account, the account name, the BIC, the payment reference and the payment terms โ each one only if the supplier sent it. Read the bank account caution below before you pay |
| Note | a summary line โ Peppol invoice received: <number> โ then the supplier's name, VAT, Peppol ID, address and stated totals, verbatim, plus your PO number and the payment details above. On a bill delivered before 21 September 2026 the summary line may be all there is; see the caution above |
| Attachments | the supplier's own PDF (or GoRoute's rendering, marked -goroute.pdf) and the original XML. On a bill delivered into Odoo 18 or earlier before 21 September 2026 these files are present but do not open; see the caution above |
The payment reference and the PO number go into their own Odoo fields only if your Odoo has those fields. GoRoute asks your Odoo rather than assuming. Where a field is absent, the value is still in the note, so nothing is lost either way.
A To-Do can be assigned to a named user by setting inbound_activity_user_id on the Odoo
connector.
The supplier's bank account, and why you should still check itโ
Where the supplier sent bank details, the bill's note now shows the account they asked to be paid into, as they sent it. It is repeated there and nowhere else: GoRoute adds it to no Odoo record, creates no bank account for the vendor, and does not set the vendor's bank account on the bill. Nothing is paid or scheduled.
Check the account against the one you already hold for that supplier before you pay it. That is the caution GoRoute writes onto the bill itself, and it is on the page for the same reason: an invoice that arrives with an account you have not seen before is how payment redirection works, and the moment to notice it is while the bill is still a draft.
If the account is one you do not recognise, confirm it with the supplier through a number or contact you already had โ not one printed on the invoice โ before paying.
"NA" is not a purchase order numberโ
Peppol's rules make a supplier fill the purchase-order field even when there is no purchase
order โ a supplier quoting only their own sales order puts the literal text NA there. Since
22 September 2026 GoRoute does not treat NA as your PO number, so it no longer lands on your
bill as the Source Document. A bill delivered before then may have NA sitting in that field,
which in Odoo is read-only once the bill exists.
The payment reference, the purchase-order number, the supplier's payment details in the note
and the NA rule are on GoRoute's production service and on its test service. They
reached test on 22 September 2026 and production later the same day, on 22 September 2026 at
22:05 UTC, when production was upgraded to the build test was already running.
A bill delivered before your service had them carries what the rest of this section describes, with the supplier's payment details in the attached XML only. Nothing is added to a bill after it is delivered.
Why taxes are emptyโ
Odoo fills in a default purchase tax on any line that arrives without one. That would put a tax on the bill the supplier did not charge โ a choice made on your behalf. GoRoute therefore sends every line with taxes explicitly empty, and copies the supplier's stated VAT and totals into the note so your accountant can apply the right tax while reviewing.
When the vendor is blankโ
GoRoute sets the vendor only when exactly one of your contacts has the supplier's Peppol ID or VAT. If none does, or several do, the vendor is left blank and the note says why โ your accountant picks the contact. GoRoute never creates contacts in your Odoo.
When lines are missingโ
If the invoice could not be read, or its currency is not active in your Odoo, the draft bill is still created โ without lines โ with the original XML attached and a note explaining why. The document always reaches your accountant.
Delivered onceโ
Each received document is delivered once, however many times delivery is retried. A retry after a partial failure completes the delivery rather than repeating it.
Invoice Responses and Oman's message-level status replies arrive on the same network endpoint but are protocol messages, not documents to pay: they are not delivered as bills.
APIโ
Every received document is also available through the API:
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/inbound-documents | List received documents; filter by status, supplier, since |
GET | /api/v1/inbound-documents/summary | Counts by status |
GET | /api/v1/inbound-documents/{id} | The received document, its parsed invoice and delivery record |
GET | /api/v1/inbound-documents/{id}/files/{kind} | One file from the document. kind is original (the XML as received), pdf (the supplier's own PDF if they attached one, otherwise GoRoute's rendering) or attachment-N (the Nth file the supplier embedded, counting from attachment-0) |
POST | /api/v1/inbound-documents/{id}/redeliver | Deliver again; completed steps are not repeated |
POST | /api/v1/inbound-documents/{id}/delivery | An external connector reports where the document landed |
The downloaded file is named after the document number: <number>.xml for original, <number>.pdf
when the supplier attached the PDF themselves, <number>-goroute.pdf when GoRoute rendered it, and
the supplier's own filename for an attachment. A 404 means that particular file is not there, and
the reason says which โ Original bytes are not stored, No PDF available, No such attachment,
Attachment is an external reference (the supplier linked the file instead of embedding it), or
Unknown file kind for any value of kind other than the three above.
Webhooks: transaction.received carries inbound_document_id; inbound.delivered fires when the
draft bill has been created.
Exception codesโ
An exception is something about a received document that a person may need to look at. It never
stops the document: GoRoute records the exception, keeps the document flowing, and delivers what it
can. Each exception has a code from the list below, a plain message, and a detail object naming
the line, party, currency or role it concerns.
The codes below are the ones GoRoute itself raises, checked against the product on 17 September
2026. A connector that runs outside GoRoute โ Xero, QuickBooks, Business Central โ reports its own
codes through POST /api/v1/inbound-documents/{id}/delivery, and those are whatever that connector
chooses to send.
| Code | What raises it | What GoRoute did as a result |
|---|---|---|
parse_failed | The document has no stored bytes to parse, or it is not well-formed XML | Nothing was parsed. The draft bill is created without lines, with the original XML attached |
document_type_unsupported | The root element is neither Invoice nor CreditNote | Parsing stopped there. No invoice was produced |
canonical_invalid | The document parsed, but the result could not be held by GoRoute's invoice model. detail lists each field and why | No invoice was produced |
party_missing | There is no AccountingSupplierParty, or no AccountingCustomerParty. detail.role says which | No invoice was produced |
no_lines | The document has no invoice lines | No invoice was produced |
totals_missing | LegalMonetaryTotal gives neither a net nor a payable amount | No invoice was produced |
party_name_missing | A party has no name. detail.role says which | The party's Peppol ID or VAT number is used as the name instead, or Unnamed seller / Unnamed buyer if it has neither |
party_endpoint_unrecognised | A party's EndpointID has no 4-digit scheme, so it is not a Peppol ID GoRoute can hold | The raw value is kept on the envelope and left out of the parsed party |
issue_date_missing | IssueDate is missing or cannot be read as a date | Today's date is used on the parsed invoice. The supplier's stated date, whatever it was, is not in it |
currency_unknown | Either the document currency is not a three-letter ISO 4217 code, or the currency is valid but not active in your Odoo โ two different causes, one code, told apart by the message | For an unreadable code, the currency is recorded as XXX. For a currency Odoo does not have, the draft bill is created without lines, and activating the currency and redelivering fixes it |
line_quantity_non_positive | A line's quantity is zero, negative or absent โ legal in UBL for returns and corrections, but not in GoRoute's model. detail carries the original | The absolute value is used, or 1 where there was no quantity at all |
line_price_negative | A line's unit price is negative. detail carries the original | The absolute value is used |
tax_category_unknown | A line's tax category is not a known UNCL5305 code | The line is recorded as standard rate. This does not put a tax on the bill โ GoRoute sends every line to Odoo with taxes empty |
duplicate_suspected | Another document from the same supplier already arrived with the same number, issue date and payable amount. detail.earlier_document_ids lists them | Nothing. The document is delivered as normal and a person decides |
delivery_failed | The connector's address was refused as unsafe, or there was no content to deliver, or the adapter itself failed | Delivery did not complete. Failures that can be retried are |
Routing on exceptionsโ
needs_attention is true whenever the document has at least one unresolved exception, and
open_exception_count is how many. Both are computed from the exception list, so they are consistent
with it and with the exceptions array in inbound.delivered, which carries the open ones only.
One thing to build around: delivery_failed is the only code GoRoute clears by itself, when a
later delivery attempt succeeds. Every other code stays open once raised, so needs_attention stays
true for the life of the record. Treat it as "something happened on the way in that a person should
see once", not as a queue that empties.