Wanted to share how we connected Frappe to SAP for an invoice-automation workflow, and open a discussion on integration patterns others have used.
The integration, in short Frappe is the front-of-house system (intake, AI extraction, human review, routing) and SAP is the system of record for posting. Frappe talks to SAP over REST for every step:
- Master/data lookups — pull PO, GRN, and service-entry (SES) data to validate an invoice before posting.
- Draft build — call an SAP endpoint that assembles the full posting draft (header + line items) from a few inputs (company code, vendor, PO, GRN, year), so SAP does the heavy lifting.
- Post — submit the draft to SAP’s MIRO posting endpoint; on success SAP returns the MIRO + Accounting document numbers, which we store back on the Frappe record.
- Document verify — for manual/edge cases, validate a document against SAP (company code + vendor match) before applying a payment block.
How it’s built on the Frappe side
- All SAP calls live behind whitelisted server methods — the desk pages never call SAP directly.
- Instant page loads from a stored draft; SAP is only hit on an explicit “Fetch” action (behind a loading overlay), so slow round-trips never block the UI.
- SAP client is resolved dynamically per call (derived from the company code) — never hardcoded.
- Credentials/base URLs in an encrypted Settings singleton, not in code or git.
- Fail-safe routing — if SAP rejects a post, the record goes to a human queue with the SAP error logged, instead of failing silently.
A few things I learned
- SAP pads/normalizes values (e.g. vendor codes to 10 digits) — doing padding-agnostic comparisons on the Frappe side avoids false mismatches (
0000010034==10034). - Year handling matters: consumed/posted GRNs behave differently, so seeding the right fiscal year on lookups saves a lot of slow retries.
- Treat SAP’s response contract as the source of truth for “success” (e.g. “a document number came back”), rather than just HTTP 200.
Questions for the community
- How are you authenticating Frappe → SAP in production — token/basic auth stored in Settings, an API gateway, or something else?
- Anyone using SAP’s OData services vs custom REST endpoints from Frappe? Trade-offs?
- Best practice for long-running SAP calls in Frappe — synchronous whitelisted method, background job + realtime update, or a queue?
Happy to share more on any part. Curious how others have wired Frappe to SAP (or other ERPs).