Infor M3 ION API Gateway OAuth 2.0 Python Client Generator
This generator writes a Python client for the on-prem ION API Gateway that reads a downloaded .ionapi file, gets an OAuth 2.0 token with service account keys, reuses it until shortly before expiry and calls one M3 MI transaction through the v2 execute endpoint. Use it for scheduled jobs and integrations that should not depend on a person's password.
Fill in
m3_ion_client.py
import json
import time
import requests
IONAPI_PATH = 'C:/ionapi/M3_Integration.ionapi'
PROGRAM = 'CRS610MI'
TRANSACTION = 'GetBasicData'
CONO = '100'
DIVI = 'AAA'
MAXRECS = '100'
RETURNCOLS = 'CUNO,CUNM,STAT'
CA_BUNDLE = '[CA bundle for your internal TLS (blank uses system store)]' or True
INPUTS_TEXT = """CUNO=10001"""
class IonClient:
def __init__(self, path):
with open(path, encoding='utf-8') as f:
self.cfg = json.load(f)
self.token = None
self.refresh = None
self.expires = 0
def _token_request(self, data):
url = self.cfg['pu'] + self.cfg['ot']
data['client_id'] = self.cfg['ci']
data['client_secret'] = self.cfg['cs']
r = requests.post(url, data=data, timeout=60, verify=CA_BUNDLE)
r.raise_for_status()
tok = r.json()
self.token = tok['access_token']
self.refresh = tok.get('refresh_token')
self.expires = time.time() + int(tok.get('expires_in', 3600)) - 60
def get_token(self):
if self.token and time.time() < self.expires:
return self.token
if self.refresh:
try:
self._token_request({'grant_type': 'refresh_token', 'refresh_token': self.refresh})
return self.token
except requests.HTTPError:
self.refresh = None
self._token_request({
'grant_type': 'password',
'username': self.cfg['saak'],
'password': self.cfg['sask'],
})
return self.token
def execute(self, program, transaction, params):
url = self.cfg['iu'].rstrip('/') + '/' + self.cfg['ti'] + '/M3/m3api-rest/v2/execute/' + program + '/' + transaction
url += ';cono=' + CONO
if DIVI:
url += ';divi=' + DIVI
query = dict(params)
query['maxrecs'] = MAXRECS
if RETURNCOLS:
query['returncols'] = RETURNCOLS
headers = {'Authorization': 'Bearer ' + self.get_token(), 'Accept': 'application/json'}
r = requests.get(url, params=query, headers=headers, timeout=120, verify=CA_BUNDLE)
r.raise_for_status()
return r.json()
def parse_inputs(text):
params = {}
for line in text.splitlines():
if '=' in line:
k, v = line.split('=', 1)
params[k.strip()] = v.strip()
return params
if __name__ == '__main__':
client = IonClient(IONAPI_PATH)
data = client.execute(PROGRAM, TRANSACTION, parse_inputs(INPUTS_TEXT))
if data.get('nrOfFailedTransactions'):
for res in data.get('results', []):
print('ERROR', res.get('errorMessage'), res.get('errorField'), res.get('errorCode'))
else:
for res in data.get('results', []):
for rec in res.get('records', []):
print(rec).ionapi keys the script reads
| Key | Used for |
|---|---|
| ti | Tenant segment in the API URL |
| ci / cs | OAuth 2.0 client id and secret |
| pu + ot | Token endpoint (SSO base URL plus token path) |
| iu | ION API Gateway base URL |
| saak / sask | Service account access key and secret key, sent as username and password |
Verify against the M3 API documentation in your ION API Gateway (the Swagger for the M3 suite): the v2 execute path, whether cono and divi are accepted as matrix parameters and maxrecs and returncols as query parameters on your version, and the exact error keys in the v2 response. The script prints the whole error entry so you see what your server returns. Keep the .ionapi file out of source control and readable only by the service account.
Get your ION API setup checked
Tell us your gateway version and the transactions you call and we will review the authorized app, service account mapping and token handling.
Optional. The tool and every export work without this. No spam.
How to use it
In ION API, create a backend service client authorized app, add a service account mapped to an M3 user, and download the credentials as a .ionapi file. Enter its path, the MI program and transaction (CRS610MI GetBasicData for a customer), the input fields one per line, the company and division, and for Lst transactions the maximum records and the columns to return. Install requests, run the script and check the printed records. Point CA_BUNDLE at your internal certificate chain if the gateway uses a private CA.
- One authorized app per integration, so you can revoke it alone
- Map the service account to an M3 user with only the MI security it needs
- Use returncols to keep responses small
Gateway versus calling the M3 BE grid directly
The classic endpoint on the M3 server, /m3api-rest/execute/PROGRAM/TRANSACTION, uses grid authentication, usually basic auth with an M3 user, and returns MIRecord lists with name and value pairs. Through ION API you call {iu}/{ti}/M3/m3api-rest/v2/execute with a bearer token instead; the gateway handles the grid authentication, logs and throttles calls, and the v2 response returns results with plain record objects. Service accounts exist so a job authenticates with revocable keys tied to one app rather than a person's password that expires or leaves with the person.
Worked example and reading the response
With CUNO=10001, company 100 and division AAA, the script calls CRS610MI GetBasicData and prints a record such as CUNO, CUNM and STAT. In the v2 response the counters nrOfSuccessfullTransactions and nrOfFailedTransactions sit at the top level, and each entry in results holds the transaction name and its records. When a call fails the entry carries an error message, and often the field that caused it; the script prints them as returned. A wrong customer number, for example, comes back as a business error rather than an HTTP failure.
Token handling and common mistakes
The token request posts grant_type password with saak and sask as username and password plus the client id and secret, to pu joined with ot. The client stores expires_in and renews one minute early, preferring the refresh token when the server issued one. Common errors are building the token URL from iu instead of pu, a service account not mapped to an M3 user, a clock skew that makes tokens look expired, and requesting a new token for every row in a loop, which slows the job and loads the authorization server.
Frequently Asked Questions
What is in an .ionapi file?
It is a JSON credentials file downloaded from ION API for an authorized app. The keys used here are ti (tenant), ci and cs (client id and secret), pu and ot (the token endpoint), iu (the gateway URL) and, for backend service apps, saak and sask (service account keys). Treat it like a password.
Where is the M3 REST API documentation or Swagger?
In ION API the M3 suite publishes API documentation with Swagger for the m3api-rest endpoints, and on the M3 server the API browser lists MI programs, transactions and fields. Use them to confirm parameter names and mandatory input fields for your version.
Why use a service account instead of a user login?
A service account ties the integration to one authorized app with keys you can rotate or revoke without touching a person's account. Its calls are attributed to the mapped M3 user, so you can give it exactly the MI security it needs and audit it separately.
How do I limit the rows and columns returned by an M3 Lst transaction?
Pass maxrecs for the row limit and returncols with a comma-separated list of output fields. Small, explicit column lists reduce response size and processing time. For more than one page of data, page by key or use a dedicated extract approach rather than a very large maxrecs.
If you want an assistant that answers M3 questions through these same ION API calls, on your own servers and with read-only defaults, we can set that up.
Related Tools
Infor M3 MI API Transaction Call Generator
Fill in program, transaction and parameters to get a ready M3 REST call as URL, curl and a JavaScript fetch snippet.
Developer ToolsInfor M3 CSV to MI API Bulk Loader Script Generator
Generate a Python loader that reads a CSV, maps columns to MI fields, calls one M3 transaction per row and writes a result file with the M3 message for every failed row.
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.
Infor M3 & CloudSuiteInfor ION BOD Verbs and Nouns Reference for M3
Look up what each ION BOD verb does, common nouns used with M3, and key ION components in plain language.
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 MI API and ION API Gateway Security ChecklistSecurity checklist for on-prem M3 13.x integrations using MI programs over REST and the ION API gateway: accounts, authorization, transport, monitoring and lifecycle.
- Infor ION API Gateway OAuth Token Request Generator (.ionapi)Turn the values in a downloaded .ionapi file into code that requests a token from the Infor authorization server, calls the ION API Gateway and revokes the token.
- Infor M3 CSV to MI API Bulk Loader Script GeneratorGenerate a Python loader that reads a CSV, maps columns to MI fields, calls one M3 transaction per row and writes a result file with the M3 message for every failed row.
ERP fixes and how-tos
- How to Call M3 API (MI Programs) Through ION APIHow to build and authenticate an ION API call to an M3 MI program: service account setup, the .ionapi file, the execute endpoint URL, and request/response shape.
- 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.
- 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 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.
- HxGN EAM and Infor M3 via Infor IONHow HxGN EAM (formerly Infor EAM) connects to Infor ERPs such as M3 through Infor ION: purchasing, inventory and payables sync, setup, pitfalls and AI uses.
- XEDI EDI Integration with Infor LN (ION BODs)How XEDI translates X12 and EDIFACT into Infor BODs routed through ION for Infor LN, plus SyteLine and M3. Setup steps, data flows, pitfalls and FAQ.
Guides
- 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.
- Infor ION Integration Patterns for M3: BODs, ION Connect, and Event-Driven ArchitectureHow Infor ION moves M3 sales and purchase orders between systems: BODs, ION Connect, API Gateway and event workflows. ION is middleware, not an order system.
- 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.
Integrations
- How to add Microsoft Teams to Infor M3Connect Infor M3 to Microsoft Teams: bots, adaptive cards, approvals and alerts through ION API and M3 MI programs, Entra ID sign-in and on-prem gateway options.
- 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.