Developer ToolsFree generatorPDF, Excel, Word exportInfor M3All Infor M3 tools

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

Generated code
Download:

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

KeyUsed for
tiTenant segment in the API URL
ci / csOAuth 2.0 client id and secret
pu + otToken endpoint (SSO base URL plus token path)
iuION API Gateway base URL
saak / saskService 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.

Was this tool useful?

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.

ArchRay builder
Design the on-prem AI stack for Infor M3: model, GPUs, RAG pipeline, guardrails
See memory, speed and cost as you swap parts, then export the diagram. Free, in your browser.
Open the builder

Keep exploring

Free tools

ERP fixes and how-tos

Runs with your ERP

Guides

AI on your ERP

Integrations

Software