Skip to main content
RapidDev - Software Development Agency
flutterflow-tutorials

How to Integrate an ERP System for Business Management in FlutterFlow

FlutterFlow connects to ERP systems (SAP, Oracle NetSuite, Odoo, Microsoft Dynamics) by proxying all API calls through a Cloud Function. The Cloud Function handles ERP authentication (OAuth 2.0, API keys, or certificate-based auth), transforms SOAP or complex REST responses into simple JSON, and exposes clean endpoints that FlutterFlow calls via the API Manager. Focus on 3-5 high-value mobile use cases — approvals, field service, inventory lookup — rather than replicating the entire ERP in mobile.

What you'll learn

  • How to proxy ERP API calls through Cloud Functions to handle authentication and data transformation
  • How to build a mobile purchase order approval workflow connected to your ERP
  • How to display real-time inventory and work order data in a FlutterFlow dashboard
  • How to cache ERP data in Firestore for field workers with unreliable connectivity
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Beginner10 min read90-120 minFlutterFlow Free+ (Cloud Functions required for ERP auth proxy)March 2026RapidDev Engineering Team
TL;DR

FlutterFlow connects to ERP systems (SAP, Oracle NetSuite, Odoo, Microsoft Dynamics) by proxying all API calls through a Cloud Function. The Cloud Function handles ERP authentication (OAuth 2.0, API keys, or certificate-based auth), transforms SOAP or complex REST responses into simple JSON, and exposes clean endpoints that FlutterFlow calls via the API Manager. Focus on 3-5 high-value mobile use cases — approvals, field service, inventory lookup — rather than replicating the entire ERP in mobile.

Build mobile ERP interfaces in FlutterFlow via Cloud Function proxy

Enterprise ERP systems like SAP, Oracle NetSuite, Odoo, and Microsoft Dynamics 365 expose APIs — but those APIs require complex authentication, often use SOAP XML or proprietary REST formats, and should never be called directly from a mobile client. A Cloud Function acting as a proxy solves all three problems: it manages OAuth token refresh, transforms ERP responses into flat JSON that FlutterFlow can bind to, and keeps credentials securely server-side. This tutorial focuses on three practical mobile use cases: a purchase order approval workflow, an inventory lookup screen, and a field service work order view — the three scenarios where mobile ERP access delivers the most immediate business value.

Prerequisites

  • Access to your ERP system's API documentation and a test or sandbox environment
  • API credentials for your ERP (OAuth client ID/secret, API key, or user account for basic auth)
  • A Firebase project with Cloud Functions enabled (Blaze billing plan required for external API calls)
  • Basic understanding of FlutterFlow's API Manager and Backend Queries

Step-by-step guide

1

Create a Cloud Function ERP proxy with authentication

Create a Cloud Function named erpProxy in your Firebase functions. For OAuth-based ERPs (Odoo, NetSuite): implement a token manager that stores the access token and refresh token in Firestore or Cloud Function memory, and refreshes the token before it expires. For API key ERPs (many REST-based systems): read the key from environment variables (firebase functions:config:set erp.key='yourkey'). For SAP: use Basic Auth with service account credentials. Structure the Cloud Function to accept a JSON body with action (e.g., 'getInventory', 'approvePO', 'getWorkOrders') and params, then route to the appropriate ERP API call. Transform the ERP response — flatten nested SAP SOAP XML or Oracle REST responses — into clean JSON objects that FlutterFlow can directly bind to widgets.

Expected result: The Cloud Function deploys and returns a successful test response from your ERP when called with sample parameters.

2

Configure the ERP API Group in FlutterFlow

In FlutterFlow, go to API Manager → Add API Group. Name it ERPProxy. Set the Base URL to your Cloud Function URL (visible in Firebase Console → Functions after deployment). Add a header: Authorization with value Bearer [firebase_id_token] so only authenticated FlutterFlow users can call your proxy. Under API Calls, add getPurchaseOrders: POST method, body {"action": "getPurchaseOrders", "status": "pending", "userId": "[userId]"}. Add approvePurchaseOrder: POST, body {"action": "approvePO", "poId": "[poId]", "approverId": "[userId]", "comments": "[comments]"}. Add getInventoryItem: POST, body {"action": "getInventory", "itemCode": "[itemCode]"}. Test each call using the Test button in the API Manager and verify the responses.

Expected result: All three API Calls test successfully and return properly structured JSON from your ERP via the Cloud Function proxy.

3

Build the purchase order approval workflow

Create a POApprovalList page. Add a Backend Query using the getPurchaseOrders API Call and bind the response to a ListView. Each list item shows: PO number, vendor name, total amount, requested date, and a status chip (color-coded: pending=amber, approved=green, rejected=red). Tap on a PO to navigate to a PODetail page passing the poId as a page parameter. On the PODetail page, display the line items in a nested ListView, the total amount, and a notes TextField. Add an Approve button and a Reject button. Both buttons call the approvePurchaseOrder API Call — the Approve button passes approved=true and the Reject button passes approved=false, both with the content of the notes field as comments. Show a success Snackbar and navigate back to the list after a successful response.

Expected result: Managers can view pending purchase orders on mobile and approve or reject them with comments, with the ERP updated in real time.

4

Add an inventory lookup screen

Create an InventoryLookup page. Add a TextField with On Submission triggering the getInventoryItem API Call with the entered item code. Display results: item description, on-hand quantity, reserved quantity, available quantity (calculated with a Custom Function: available = onHand - reserved), warehouse location, and reorder point with a low-stock warning icon (show if available < reorderPoint). Add a barcode scan button using a Custom Action with the mobile_scanner package that fills the item code TextField automatically after scanning a product barcode. This is particularly useful for warehouse staff doing physical inventory counts on a mobile device.

Expected result: Warehouse staff can enter or scan an item code to instantly retrieve current inventory levels and location from the ERP.

5

Cache ERP data in Firestore for offline access

Field service technicians often work in areas with unreliable connectivity. Add a sync mechanism: when the user opens the app with internet access, call getWorkOrders API and write results to Firestore collection erp_work_orders (one document per order, keyed by orderId). In the WorkOrderList page, use a Firestore Backend Query instead of the direct API call — Firestore has offline persistence enabled by default on mobile, so data is readable even without internet. Show a sync timestamp at the top of the page. Add a Refresh button that re-calls the ERP API and updates Firestore. For write operations (updating work order status, logging time), write to a pending_updates Firestore collection and add logic in the Cloud Function to flush pending updates to the ERP when connectivity is restored.

Expected result: Work orders remain viewable offline. The app shows a 'Last synced X minutes ago' indicator and the Refresh button syncs when internet is available.

Complete working example

erp_proxy_cloud_function.js
1// Cloud Function: erpProxy
2// Proxies calls to Odoo ERP via JSON-RPC
3const functions = require('firebase-functions');
4const axios = require('axios');
5
6const ERP_URL = functions.config().erp.url;
7const ERP_DB = functions.config().erp.db;
8const ERP_USER = functions.config().erp.user;
9const ERP_PASS = functions.config().erp.password;
10
11let _sessionToken = null;
12
13async function getOdooSession() {
14 if (_sessionToken) return _sessionToken;
15 const resp = await axios.post(`${ERP_URL}/web/session/authenticate`, {
16 jsonrpc: '2.0', method: 'call', id: 1,
17 params: { db: ERP_DB, login: ERP_USER, password: ERP_PASS },
18 });
19 _sessionToken = resp.headers['set-cookie'];
20 return _sessionToken;
21}
22
23exports.erpProxy = functions.https.onRequest(async (req, res) => {
24 if (req.method !== 'POST') return res.status(405).send('POST only');
25
26 const { action, params = {} } = req.body;
27 const cookie = await getOdooSession();
28
29 try {
30 if (action === 'getPurchaseOrders') {
31 const resp = await axios.post(
32 `${ERP_URL}/web/dataset/call_kw`,
33 {
34 jsonrpc: '2.0', method: 'call', id: 2,
35 params: {
36 model: 'purchase.order',
37 method: 'search_read',
38 args: [[['state', '=', 'to approve']]],
39 kwargs: { fields: ['name','partner_id','amount_total','date_order','state'], limit: 50 },
40 },
41 },
42 { headers: { Cookie: cookie } }
43 );
44 return res.json({ orders: resp.data.result });
45 }
46
47 if (action === 'approvePO') {
48 await axios.post(
49 `${ERP_URL}/web/dataset/call_kw`,
50 {
51 jsonrpc: '2.0', method: 'call', id: 3,
52 params: {
53 model: 'purchase.order',
54 method: 'button_approve',
55 args: [[params.poId]],
56 kwargs: {},
57 },
58 },
59 { headers: { Cookie: cookie } }
60 );
61 return res.json({ success: true });
62 }
63
64 return res.status(400).json({ error: 'Unknown action' });
65 } catch (err) {
66 _sessionToken = null; // reset on error
67 return res.status(500).json({ error: err.message });
68 }
69});

Common mistakes

Why it's a problem: Trying to replicate the entire ERP UI in FlutterFlow

How to avoid: Identify 3-5 high-value use cases where mobile access provides specific benefits: approvals (managers approve from anywhere), field service (technicians view work orders without a laptop), inventory (warehouse staff scan items with phones). Build only those screens, integrating with the ERP for the specific data they need.

Why it's a problem: Making ERP API calls directly from the FlutterFlow client

How to avoid: All ERP calls go through a Cloud Function proxy. The Cloud Function manages authentication, handles SOAP-to-JSON transformation, and exposes simple REST endpoints that FlutterFlow can call without any ERP-specific logic on the client.

Why it's a problem: Not handling ERP API failures gracefully in the FlutterFlow UI

How to avoid: Add loading states and explicit error messages to every API-backed screen. Show the last cached Firestore data with a 'Data may be outdated' banner when the live ERP call fails. Implement retry logic with a Retry button rather than requiring the user to navigate away and back.

Best practices

  • Always build a test environment first using your ERP's sandbox — mistakes in a production ERP (accidental PO approvals, inventory adjustments) can have real financial consequences
  • Log all API calls to Firestore with timestamp, user, action, and response status — ERP integrations require audit trails for financial compliance
  • Use Firestore as an intermediate cache for frequently read ERP data (product catalog, vendor list) and only call the ERP for writes and real-time inventory checks
  • Implement role-based access in Firestore Security Rules to mirror ERP permissions — not every mobile user should see every ERP record
  • Add a maintenance mode banner to all ERP-connected screens — ERP systems have regular maintenance windows, and you should be able to display a message without a code deployment
  • Consider data residency requirements — some ERP data (financial records, employee data) may have legal restrictions on where it can be stored, which affects whether Firestore (US by default) is appropriate for caching
  • Paginate all list queries — production ERP databases have thousands of records per module, and fetching all at once will time out and exhaust memory

Still stuck?

Copy one of these prompts to get a personalized, step-by-step explanation.

ChatGPT Prompt

I am building a FlutterFlow app that connects to an Odoo ERP system via a Cloud Function proxy. Write a Node.js Cloud Function that: (1) authenticates to Odoo using JSON-RPC with username/password, caches the session cookie, (2) exposes a POST endpoint that accepts an 'action' field in the request body, (3) handles the actions 'getPurchaseOrders' (returns pending POs with id, name, vendor, amount, date) and 'approvePO' (calls button_approve on a given PO id). Include session refresh on auth failure.

FlutterFlow Prompt

Create a purchase order approval list page in my FlutterFlow app. Use a Backend Query calling my ERPProxy API Group's getPurchaseOrders endpoint. Display results in a ListView showing PO number, vendor name, and amount. Each item should navigate to a detail page passing the poId parameter. On the detail page, add Approve and Reject buttons that call the approvePurchaseOrder API Call and show a success Snackbar.

Frequently asked questions

Which ERP systems can FlutterFlow connect to?

Any ERP with an API — SAP Business One and S/4HANA (REST/SOAP), Oracle NetSuite (REST), Odoo (JSON-RPC), Microsoft Dynamics 365 (REST via Microsoft Graph), Sage 300 (REST), and many others. The Cloud Function proxy pattern works for any ERP that has HTTP-accessible APIs. The Cloud Function handles the authentication and protocol differences so FlutterFlow only sees clean REST JSON.

How do I handle ERP data that needs to work offline on mobile?

Use Firestore as an offline cache. When the app starts with internet access, sync relevant ERP records (work orders assigned to this user, their customer list, product catalog) to Firestore. FlutterFlow Backend Queries against Firestore work offline because Flutter's Firestore SDK caches data locally. For writes made offline, store them in a pending_actions Firestore collection and process them in a Cloud Function when connectivity returns.

Do I need a special ERP license or add-on to use the API?

It depends on your ERP. SAP has a separate API licensing structure (SAP Integration Suite). Oracle NetSuite includes REST API access on standard licenses but has per-request limits. Odoo Community is open-source with full API access; Odoo Enterprise requires proper licensing. Microsoft Dynamics 365 requires appropriate Dataverse API capacity. Always check your ERP license agreement before building API integrations to avoid surprise licensing costs.

Can FlutterFlow write data back to the ERP?

Yes — write operations go through the same Cloud Function proxy. The Cloud Function calls the ERP's create, update, or approve endpoints. For transactional integrity, implement a write queue in Firestore: the FlutterFlow app writes to a pending_updates collection, and the Cloud Function picks up these pending updates and submits them to the ERP, marking them as completed or failed. This pattern handles connectivity loss gracefully.

How long do ERP API calls take?

ERP APIs are notoriously slower than web APIs. SAP and Oracle can take 2-8 seconds for complex queries, especially on shared hosting plans. Always show a loading indicator and add a timeout in your Cloud Function (30 second maximum for Firebase Cloud Functions HTTP triggers). Mitigate slow calls by caching read-heavy data in Firestore and only calling the ERP live for writes and real-time stock queries.

Can RapidDev build a custom ERP mobile interface for our business?

Yes. ERP mobile integrations with real-time sync, offline capability, barcode scanning, and role-based access across multiple ERP modules are complex projects that benefit significantly from specialist experience. RapidDev has built ERP-connected FlutterFlow apps for manufacturing, distribution, and field service companies. Contact us with your ERP system, required modules, and user count for a scoping estimate.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.