Infor M3 CSV to MI API Bulk Loader Script Generator (Python)
This generator writes a Python loader that reads a CSV, maps columns to MI input fields and calls one M3 transaction per row through m3api-rest, logging success or the M3 message for every row. It suits loads of a few hundred to tens of thousands of records where a standard M3 import or MEC flow would be overkill.
Fill in
m3_bulk_load.py
import csv
import os
import time
import requests
BASE_URL = 'https://m3be.acme.local:21108/m3api-rest/execute'
AUTH_MODE = 'basic'
USER = 'M3LOADER'
PROGRAM = 'CRS610MI'
TRANSACTION = 'Add'
CSV_PATH = 'customers.csv'
CONO = '100'
DELAY = 100 / 1000.0
DRY_RUN = 'yes' == 'yes'
MAPPING_TEXT = """customer_no=CUNO
name=CUNM
language=LNCD
currency=CUCD"""
mapping = {}
for line in MAPPING_TEXT.splitlines():
if '=' in line:
col, field = line.split('=', 1)
mapping[col.strip()] = field.strip()
s = requests.Session()
s.headers['Accept'] = 'application/json'
if AUTH_MODE == 'basic':
s.auth = (USER, os.environ['M3_PASSWORD'])
else:
s.headers['Authorization'] = 'Bearer ' + os.environ['M3_TOKEN']
url = BASE_URL.rstrip('/') + '/' + PROGRAM + '/' + TRANSACTION + ';cono=' + CONO
def call(params):
r = s.get(url, params=params, timeout=60)
try:
body = r.json()
except ValueError:
body = {}
if r.status_code != 200:
return False, 'HTTP ' + str(r.status_code) + ': ' + r.text[:300]
# classic m3api-rest error shape
if body.get('@type') == 'ServerReturnedNOK' or 'Message' in body:
return False, str(body.get('Message', body))
# v2 error shape (if BASE_URL points at a v2 endpoint)
if body.get('nrOfFailedTransactions'):
res = (body.get('results') or [{}])[0]
return False, str(res.get('errorMessage', res))
return True, 'OK'
ok = failed = 0
with open(CSV_PATH, newline='', encoding='utf-8-sig') as src, open('load_result.csv', 'w', newline='', encoding='utf-8') as out:
reader = csv.DictReader(src)
writer = csv.writer(out)
writer.writerow(['row', 'status', 'message'] + list(mapping.values()))
for n, row in enumerate(reader, start=2):
params = {field: (row.get(col) or '').strip() for col, field in mapping.items()}
if DRY_RUN:
writer.writerow([n, 'DRY RUN', url] + list(params.values()))
continue
success, msg = call(params)
if success:
ok += 1
else:
failed += 1
writer.writerow([n, 'OK' if success else 'ERROR', msg] + list(params.values()))
time.sleep(DELAY)
print('dry run' if DRY_RUN else 'done', '- ok:', ok, 'failed:', failed, '- see load_result.csv')Run it with dry run first, then against a non-production company. Verify in the M3 API repository (MRS001 and its transaction fields) or the API browser on your server: the transaction name, its mandatory input fields and field lengths. Verify the error shape your 13.x m3api-rest returns for a rejected Add (the script checks the classic Message key and the v2 counters). Numbers and dates must be in the format the API expects, dates usually YYYYMMDD.
Get your load plan reviewed
Send the transaction, field mapping and row count and we will check mandatory fields, formats and the run window before you load.
Optional. The tool and every export work without this. No spam.
How to use it
Set the base URL of m3api-rest on your M3 13.x server, the authentication mode, the MI program and transaction (CRS610MI Add for customers, MMS200MI transactions for items, PPS200MI AddLine for purchase order lines), and the CSV path. Map each CSV column to its MI field with one csvcol=MIFIELD line. Leave dry run on for the first pass: it writes load_result.csv with the URL and parameters per row without calling M3. Set M3_PASSWORD or M3_TOKEN as an environment variable rather than in the file.
- Row numbers in the result file match spreadsheet rows (header is row 1)
- Fix failed rows in the source CSV and rerun only those
- Keep the delay above zero on shared servers
How errors are detected
M3 can answer HTTP 200 for a rejected business transaction, so the status code alone is not enough. The classic m3api-rest endpoint returns an error object with a Message text (and a NOK type) instead of records; a v2 endpoint reports nrOfFailedTransactions and puts an error message in the result entry. The call function checks the status code first, then both shapes, and writes the message as returned, for example a duplicate customer number or a missing mandatory field.
Worked example and duration
Loading 2,000 customers with CRS610MI Add at around 100 ms per call plus a 100 ms delay takes roughly 2,000 x 0.2 s, about 7 minutes. Real call times vary with transaction complexity, validation and server load; the M3 MI API batch load time estimator lets you model that before you schedule. Run loads outside nightly batch peaks so you do not compete with MRP or invoicing jobs, and check a sample of created records on the M3 panel afterwards.
Common mistakes
Values longer than the API field length are rejected or truncated: check lengths in the API repository before loading. Leading zeros disappear when the CSV was saved from a spreadsheet. Decimal commas from European locales break numeric fields. Loading into the production company by mistake is the costly one, which is why CONO is explicit in the URL. Add transactions cannot be undone by rerunning the script, so a failed partial load needs a clean-up plan.
Frequently Asked Questions
Can I use MI APIs for third party integration with M3?
Yes. MI programs are the published interface for reading and writing M3 business objects, and external systems call them through m3api-rest on the M3 server or through ION API. For event-driven flows between systems, ION with BODs or MEC mappings may fit better than direct calls.
How fast can I load data through M3 MI APIs?
One call per row, so duration is rows times call time plus any delay. Simple Add calls often take tens to a few hundred milliseconds each. Measure 50 rows in your environment and extrapolate, then schedule the load outside batch peaks.
Why does M3 return success with an error message?
m3api-rest separates transport from business result. A call can reach M3 and return HTTP 200 while the transaction is rejected, for example for a duplicate key or a missing field. Always inspect the response body for the error message, as this script does.
Should I use a dry run before an M3 data load?
Yes. A dry run shows exactly which parameters each row would send, so you catch wrong mappings, empty mandatory columns and formatting problems before anything is created. Follow it with a small real run in a test company.
If you want loads like this reviewed or run with approval steps, or an assistant that answers questions about M3 data on your own servers, we can help.
Related Tools
M3 MI API Batch Load Time Estimator
Estimate how long a bulk load through M3 APIs will run and how added parallel threads change it, using your own measured response time.
Infor M3 & CloudSuiteInfor M3 Item Master Upload Worksheet
Collect and validate item master data for an M3 load, with status checks and a ready-to-export Excel or CSV layout.
Developer ToolsInfor M3 ION API Gateway OAuth 2.0 Python Client Generator
Generate a Python script that loads your .ionapi credentials file, gets and reuses an OAuth 2.0 token, and calls an M3 MI transaction through the on-prem ION API Gateway.
Developer ToolsInfor M3 EXPORTMI Select Query Generator
Fill in table, columns and filter to get a working EXPORTMI Select call for M3 13.x on-prem, plus a Python loop that pages by key range past the 10,000 record cap.
More Developer Tools tools
See all- Infor M3 H5 Script TypeScript Template Generator
- Infor M3 MDBREADMI and Custom List API Design Worksheet
- Infor M3 EXPORTMI Extraction Call Volume Calculator
- SAP Sales Order ABAP SELECT Generator (VBAK, VBAP, VBFA)
- SAP Sales Order Create BAPI ABAP Generator (BAPI_SALESORDER_CREATEFROMDAT2)
- SAP ABAP Open Items SELECT Generator
- SAP ACDOCA SQL Query Generator
- SAP QM Inspection Lot ABAP SELECT Generator
- SAP Quality Notification Pareto SQL Query Generator
Keep exploring
Free tools
- Infor M3 H5 Script TypeScript Template GeneratorGenerate a starting H5 script class that reads a field on an M3 panel, calls an MI transaction and shows the answer on the panel, on load or before Enter.
- Infor M3 MI API Transaction Call GeneratorFill in program, transaction and parameters to get a ready M3 REST call as URL, curl and a JavaScript fetch snippet.
- Infor M3 ION API Gateway OAuth 2.0 Python Client GeneratorGenerate a Python script that loads your .ionapi credentials file, gets and reuses an OAuth 2.0 token, and calls an M3 MI transaction through the on-prem ION API Gateway.
ERP fixes and how-tos
- Infor M3 SDK, MI APIs and REST API Documentation GuideDeveloper map of the Infor M3 SDK: MI programs, the REST API through ION API, authentication, example calls, and where to find the official documentation.
- Private AI Layer for Infor M3 On-Prem: Reference ArchitectureReference architecture to add a private AI assistant to Infor M3 on-prem: data access paths, retrieval, permissions, sizing and rollout, no cloud needed.
- Infor M3 API Swagger: Discover MI Programs, Authenticate and Test CallsHow to find M3 MI programs and REST APIs through the ION API Swagger and OpenAPI documentation, authenticate with an ionapi file, and test your first call.
Runs with your ERP
- Infor M3 Scheduling Workbench and M3: finite scheduling explainedHow Infor M3 Scheduling Workbench schedules against capacity and materials and writes orders back to M3 via PSMI, with setup, pitfalls and AI help.
- ecosio EDI and Infor M3: orders, dispatch advices and invoicesHow ecosio managed EDI connects to Infor M3 for orders, dispatch advices and invoices: API link, message tracking, setup, pitfalls and private AI.
- Infor EDI Managed Service and Infor M3 over IONHow Infor's EDI managed service connects to Infor M3 through ION with pre-built trading partner links: data flows, setup steps, pitfalls and a private AI layer.
Guides
- Infor M3 API Toolkit: A Developer's Guide to MI Programs and MvxAPIBuild robust integrations with the Infor M3 API toolkit. Learn MI programs, MvxAPI patterns, and transaction handling for M3 13.4+ environments.
- Infor M3 API Performance Optimization GuideOptimize Infor M3 API performance. MI program tuning, API call batching, caching strategies, and connection pool management for high-volume integrations.
- Infor M3 API Integration with MI Programs and RESTInfor M3 API integration guide covering MI programs, the m3api-rest v2 endpoint, ION API gateway OAuth, Event Hub, and error handling for reliable interfaces.
AI on your ERP
- Infor M3 AI: A Practical Path from MI Programs to a Private AssistantInfor M3 AI explained: grounded natural-language answers over MI programs and MEC, agents for distribution and manufacturing, on-prem or EU private cloud.
- Infor M3 Supply Chain Planning With AI That Explains the MRP OutputAI for Infor M3 supply chain planning: explain MRP action messages, review planned orders, and trace shortages through MITBAL and MITMAS on private infrastructure.
Integrations
- How to add AI agents to Infor M3How to add AI agents to Infor M3: a tool layer over MI programs and ION, read-first workflows for POs, MO and CO exceptions, and human approval on writes.
- How to build an MCP server for Infor M3How to build a Model Context Protocol server for Infor M3: which read-only tools to expose over MI programs, ION or on-prem auth, transports, scoping and audit.