Odoo and BILL integration
Odoo runs your accounting and purchasing. BILL automates your accounts payable. Connecting them keeps supplier records in agreement and moves purchase orders from Odoo directly into BILL for approval and payment, without manual re-entry. When BILL records a payment, the entry flows back into Odoo so your general ledger reflects cash spent. ml-connector handles the different authentication models on each side and syncs on a schedule you set.
What moves between them
The main flow is Odoo into BILL. Odoo vendors and purchase orders sync into BILL as vendors and bills on a customer-configured schedule. When BILL records a payment, ml-connector reads the payment event (via webhook if enabled, or by polling the payments endpoint) and writes the payment back into Odoo as an account.payment record, allocated to the matching vendor and GL account. Recurring bills in BILL are read-only, so ml-connector does not write them back to Odoo. Reference data such as chart of accounts and vendor master is validated in both directions to ensure every payment references a GL account and vendor that exist in Odoo.
How ml-connector handles it
ml-connector stores both credential sets encrypted. For Odoo, the integration user's API key is paired with the username to authenticate into the customer's instance; for Odoo 19+, the API key is passed as a Bearer token in the Authorization header, and for older versions the key is included in XML-RPC payloads after obtaining a uid via authenticate(). For BILL, the session token is obtained at the start of each batch by calling POST /v3/login and is refreshed before expiry. Odoo's lack of built-in webhooks means ml-connector polls for new purchase orders and vendors using write_date filters with high-water-mark timestamps, capturing all changes since the last run. BILL webhook events (if enabled) push bill.created and payment.updated notifications; ml-connector verifies the HMAC-SHA256 signature header x-bill-sha-signature using the stored securityKey. BILL sessions expire after 35 minutes, so ml-connector obtains a fresh token before each batch or refreshes mid-batch if a 401 is returned. Vendors are matched by name and domain in both systems; if a vendor exists only in Odoo, it is created in BILL with a reference to the Odoo partner ID. Purchase orders in Odoo are converted to BILL bills, with line items mapped to BILL line fields. Every record carries a full audit trail and can be replayed if a downstream call fails.
A real-world example
A mid-sized supply chain business uses Odoo for accounting and purchasing across two regional offices, and has standardized on BILL for centralized accounts payable and payment orchestration. Before the integration, the AP team received purchase orders from Odoo, re-entered them manually into BILL, and reconciled BILL payments back to Odoo each month. With Odoo and BILL connected, each purchase order flows automatically into BILL for approval and payment routing, and BILL payments post back into Odoo's general ledger immediately, eliminating manual data entry and month-end reconciliation delays.
What you can do
- Sync Odoo vendors and purchase orders into BILL as vendor master records and bills, with line-item detail preserved.
- Read BILL payments via webhook or polling and post them back into Odoo as account.payment records, matched to the originating vendor and GL account.
- Handle Odoo API key and session-based authentication, refreshing BILL session tokens before expiry to avoid outages.
- Validate vendors and GL accounts in both systems before syncing, ensuring payments land on accounts that exist in Odoo.
- Poll Odoo purchase orders and vendors on a schedule, with full audit trails and error replay on failed downstream writes.
Questions
- Which direction does data move between Odoo and BILL?
- The main flow is Odoo into BILL. Vendors and purchase orders sync from Odoo to BILL on a schedule. When BILL records a payment, ml-connector reads the payment and posts it back into Odoo as an account.payment record, keeping the cash position aligned. Recurring bills in BILL are read-only and do not sync back to Odoo.
- How does ml-connector handle Odoo's lack of webhooks?
- Odoo has no production-grade webhooks in core, so ml-connector polls purchase orders and vendors using write_date filters with high-water-mark timestamps, capturing changes since the last run. BILL can push payment events via webhook if enabled; ml-connector verifies the HMAC-SHA256 signature on each event to confirm authenticity.
- How are BILL session tokens managed, given the 35-minute expiry?
- ml-connector obtains a fresh BILL session token at the start of each batch by calling POST /v3/login with stored credentials. If a call returns 401 during a batch, the token is refreshed immediately before retrying, ensuring no payment or bill sync fails due to expiry.
Related integrations
More Odoo integrations
Other systems that connect to BILL
Connect Odoo and BILL
Free to use. Add your credentials, ping your real systems, and see if we fit.
Get started