ml-connector
SAP S/4HANABILL

SAP S/4HANA and BILL integration

SAP S/4HANA runs the books and the procurement record. BILL runs vendor payments and accounts payable workflow. Connecting the two lets approved supplier invoices in SAP S/4HANA flow into BILL for payment without re-keying, and lets the payments BILL clears post back into SAP S/4HANA as journal entries. Vendor master data stays aligned so every bill in BILL points at a vendor SAP already knows, and payment status returns to finance automatically. ml-connector handles the very different APIs on each side and moves the data on the schedule you set.

How SAP S/4HANA works

SAP S/4HANA Cloud exposes suppliers and customers as Business Partners, supplier invoices, purchase orders, GL accounts, cost centers, and journal entries through OData V2 and V4 services on a tenant-specific URL such as https://my123456-api.s4hana.ondemand.com. System-to-system access uses OAuth 2.0 client credentials with short-lived bearer tokens, and an SAP admin must first activate a Communication Arrangement for each service before its endpoint responds. Every write (POST, PUT, PATCH, DELETE) requires an X-CSRF-Token fetched from a prior GET. SAP S/4HANA does not push native webhooks for cloud connectors, so records are read by polling with a $filter on LastChangeDateTime. There is no OData API for initiating outbound payments.

How BILL works

BILL exposes vendors, bills, payments, customers, invoices, and a chart of accounts through its REST v3 API at https://gateway.prod.bill.com/connect, with JSON bodies and standard HTTP verbs. Authentication is a session token, not OAuth2: the connector calls the login endpoint with a developer key plus org email, password, and organization ID, then sends the returned sessionId on each call. Sessions expire after 35 minutes of inactivity, so the connector re-logs in on a 401. BILL pushes webhooks for events such as bill.created, payment.updated, and payment.failed, signed with HMAC-SHA256 in the x-bill-sha-signature header. BILL has no purchase order object; POs from the ERP are represented as bills.

What moves between them

The main flow runs from SAP S/4HANA into BILL. ml-connector reads approved supplier invoices and their vendor Business Partners from SAP and creates matching vendors and bills in BILL, mapping each line to a BILL chart-of-accounts entry. Because BILL has no purchase order object, purchase orders that drive a bill are represented on the BILL side as bill line detail rather than as separate PO records. Payment data returns from BILL into SAP: when BILL reports a payment as cleared, ml-connector posts a journal entry into SAP against the GL accounts and cost centers that match the original invoice. Vendor master data is aligned in both directions so a bill never references a vendor SAP does not recognize. SAP GL accounts and cost centers are read as reference data and are not written from BILL.

How ml-connector handles it

ml-connector stores both credential sets encrypted. On the SAP side it requests an OAuth2 token from the tenant token URL, reuses it until it nears expiry, and fetches an X-CSRF-Token plus session cookies before any write, re-fetching and retrying if a write returns 403. On the BILL side it logs in for a sessionId and silently re-authenticates when a call returns 401, since BILL gives no explicit session-expired code. Because SAP S/4HANA has no webhooks for cloud connectors, the connector polls supplier invoices with a $filter on LastChangeDateTime on the cadence you choose, while BILL payment and bill webhooks (verified by recomputing the HMAC over the minified JSON body) trigger the return path as soon as a payment clears, with a scheduled poll backfilling anything a webhook misses. Vendors and GL accounts and cost centers are mapped first so every bill and journal line lands on values that already exist on both sides. BILL allows only three concurrent calls per org, so ml-connector throttles to stay inside that limit and backs off on the 20,000-per-hour ceiling, and it relies on SAP duplicate-invoice detection and BILL entity IDs to avoid posting the same record twice, since neither side offers an idempotency key.

A real-world example

A mid-sized professional services firm of roughly 300 staff runs SAP S/4HANA Cloud for its general ledger and procurement and uses BILL to schedule and pay vendor invoices through ACH and check. Before the integration, an AP clerk exported approved invoices from SAP and re-entered each one into BILL by hand, then, after BILL paid them, typed the cleared payments back into SAP to keep the ledger current. The double entry was slow and a common source of mismatched amounts and missed payment dates. With SAP S/4HANA and BILL connected, approved supplier invoices flow into BILL as bills automatically, payments come back into SAP as journal entries against the right accounts, and the clerk reviews exceptions instead of re-keying every document.

What you can do

  • Push approved supplier invoices from SAP S/4HANA into BILL as bills, mapped to the correct chart-of-accounts entries.
  • Keep vendor master data aligned so every BILL bill points at a vendor SAP S/4HANA already recognizes.
  • Post cleared BILL payments back into SAP S/4HANA as journal entries against the matching GL accounts and cost centers.
  • Bridge SAP OAuth2 token refresh and the X-CSRF-Token requirement with BILL session login and webhook signature checks.
  • Poll SAP supplier invoices on your schedule and react to BILL payment webhooks, throttled within BILL's concurrency and hourly limits.

Questions

Which direction does data move between SAP S/4HANA and BILL?
Supplier invoices and vendors move from SAP S/4HANA into BILL so finance can pay the bills there. Cleared payments move back from BILL into SAP S/4HANA as journal entries against the original GL accounts and cost centers. Vendor records are aligned in both directions, while SAP GL accounts and cost centers are read as reference data and are not written from BILL.
How does the integration handle authentication when the two systems use different models?
SAP S/4HANA uses OAuth 2.0 client credentials with short-lived tokens, and every write also needs an X-CSRF-Token fetched from a prior GET. BILL instead uses a session token from a login call that expires after 35 minutes of inactivity. ml-connector stores both credential sets encrypted, refreshes the SAP token and CSRF token as needed, and re-logs into BILL automatically whenever a call returns 401.
What happens to purchase orders, since BILL does not have them?
BILL has no purchase order object, so purchase orders are kept in SAP S/4HANA as the system of record. When a supplier invoice tied to a purchase order is pushed into BILL, the connector represents the relevant detail on the BILL bill rather than creating a separate PO record. This matches BILL's AP-centric design, where the ERP owns procurement and BILL owns payment.

Related integrations

Connect SAP S/4HANA and BILL

Free to use. Add your credentials, ping your real systems, and see if we fit.

Get started