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

Infor M3 EXPORTMI Select Query Generator (REST URL, curl and paging loop)

This generator builds an EXPORTMI Select call for M3 Business Engine 13.x on-prem: the decoded query, the REST request, a curl command and a Python loop that pages by key range. Use it when no standard Lst transaction returns the columns you need from a single table.

Fill in

Example only: use the HTTPS port your M3 BE grid exposes for m3api-rest.

MITMAS uses index 00. MITMAS80 would use index 80.

Generated code
Download:

Decoded QERY (first page)

MMITNO,MMITDS,MMSTAT from MITMAS where MMSTAT = '20'

HTTP request (URL-encode SEPC and QERY before sending)

GET https://m3be.acme.local:21108/m3api-rest/execute/EXPORTMI/Select;cono=100;maxrecs=10000?SEPC=<encoded ;>&HDRS=1&QERY=<url-encoded query above>
Authorization: Basic <base64 of M3SRVINT:password>
Accept: application/json

curl (encodes the parameters for you)

curl -s -G -u "M3SRVINT" -H "Accept: application/json" \
  "https://m3be.acme.local:21108/m3api-rest/execute/EXPORTMI/Select;cono=100;maxrecs=10000" \
  --data-urlencode "SEPC=;" \
  --data-urlencode "HDRS=1" \
  --data-urlencode "QERY=MMITNO,MMITDS,MMSTAT from MITMAS where MMSTAT = '20'"

Next page by key range (decoded QERY)

MMITNO,MMITDS,MMSTAT from MITMAS where MMSTAT = '20' and MMITNO > 'A-10450'

Python: page through the whole table by key range

import os
import requests

BASE = 'https://m3be.acme.local:21108/m3api-rest/execute/EXPORTMI/Select;cono=100;maxrecs=10000'
COLUMNS = 'MMITNO,MMITDS,MMSTAT'
KEY = 'MMITNO'
SEP = ';'
PAGE = 10000

cols = [c.strip() for c in COLUMNS.split(',')]
key_idx = cols.index(KEY)

s = requests.Session()
s.auth = ('M3SRVINT', os.environ['M3_PASSWORD'])
s.headers['Accept'] = 'application/json'

rows = []
last = ''
while True:
    q = COLUMNS + ' from MITMAS where MMSTAT = '20''
    if last:
        q += ' and ' + KEY + " > '" + last + "'"
    r = s.get(BASE, params={'SEPC': SEP, 'HDRS': '0', 'QERY': q}, timeout=300)
    r.raise_for_status()
    data = r.json()
    if 'Message' in data and 'MIRecord' not in data:
        raise SystemExit('M3 error: ' + data['Message'])
    recs = data.get('MIRecord', [])
    if not recs:
        break
    for rec in recs:
        rows.append(rec['NameValue'][0]['Value'])
    last = rows[-1].split(SEP)[key_idx].strip()
    print('fetched', len(rows), 'rows, last key', last)
    if len(recs) < PAGE:
        break

with open('MITMAS_export.csv', 'w', encoding='utf-8') as f:
    f.write(SEP.join(cols) + '\n')
    for line in rows:
        f.write(line + '\n')

Verify on your 13.x server before relying on it: the base path and port of m3api-rest on your grid, that matrix parameters cono and maxrecs are accepted (they are on the classic m3api-rest execute endpoint), and the JSON shape (MIRecord list with NameValue pairs). EXPORTMI reads one table only, needs a table that contains the company field, and does not allow a company filter: set the company on the session instead. Keywords from, where, and, or must be lowercase with one space on each side, and so must operators.

Get your extract query reviewed

Send the table, filter and volume and we will check the index choice and paging approach against your M3 13.x setup.

Optional. The tool and every export work without this. No spam.

Was this tool useful?

How to use it

Enter the host and port of m3api-rest, the table and the columns you want, always with the table prefix (MMITNO, not ITNO). Write the filter without the company field: EXPORTMI does not support company selection and always uses the company of the API session, which the generator sets with the cono matrix parameter. Pick a separator for SEPC and whether the first record should carry column names (HDRS = 1). The curl block URL-encodes the parameters for you, which avoids the most common failure: an unencoded quote, semicolon or space in QERY.

  • List columns explicitly; select * is allowed but slower
  • Keep the output to roughly 10 fields or fewer for speed
  • Use the index suffix (for example MITMAS80) when your filter matches that index
  • Lowercase from, where, and, or, each with single spaces around them

The 10,000 record cap and key-range paging

Infor documents that EXPORTMI returns at most 10,000 records per call, except when you name an index with filter values that match it. The safe pattern for a large table is to page by the leading key of the index. MITMAS read through index 00 comes back in item number order, so after each page you take the last MMITNO and ask for MMITNO greater than that value. The Python block does exactly this with HDRS = 0 on every call, stops when a page returns fewer rows than the page size, and writes one CSV. Include the key field in your column list, or the loop cannot read the last value.

Worked example

For company 100, active items (status 20) with number, description and status: QERY is MMITNO,MMITDS,MMSTAT from MITMAS where MMSTAT = '20'. With SEPC ; and HDRS 1 the first record holds the column names, then each record is one delimited row in a single output field. If the call returns exactly 10,000 rows, run the next-page query with the last item number, for example MMITNO > 'A-10450'. Check the first and last rows of each page on the MMS001 panel to confirm the filter did what you expected.

Performance and when to use something else

An unindexed filter makes EXPORTMI scan the table, which is slow on MITTRA, FGLEDG or similar large files and competes with interactive users. If you read the same table repeatedly with the same keys, add an MDBREADMI transaction on an existing index through MRS001, MRS002 and MRS003 instead: it is the API Infor recommends when no standard API exists. For full-table extracts every night, a replicated reporting database or Data Lake is cheaper than any API loop. Joins are not possible in EXPORTMI; use a CMS100MI custom list for those.

Frequently Asked Questions

How do I page through more than 10,000 records with the Infor M3 API?

EXPORTMI and CMS100MI return at most 10,000 records per call. Page by key range: sort by an index, take the last key value from the page and request key greater than that value until a page comes back short. Using an index that matches your filter is both faster and the documented exception to the cap.

What do SEPC, HDRS and QERY mean in EXPORTMI Select?

SEPC is the separator between field values: blank gives fixed-width output with trailing spaces, any character gives trimmed delimited values. HDRS = 1 makes the first record contain the field names. QERY is the SQL-like query without the word select, for example MMITNO,MMITDS from MITMAS where MMSTAT = '20'.

Why does my EXPORTMI query return nothing or an error?

Typical causes are field names without the table prefix, uppercase AND or WHERE, missing spaces around operators, a company field in the filter, or a query that was not URL-encoded so a semicolon or quote broke the request. Also check the user's company: EXPORTMI only reads the session company.

Can EXPORTMI join two M3 tables?

No. EXPORTMI reads one table and the table must contain the company field. For a join, define a CMS100MI custom list, or read each table separately and join in your integration layer. For repeated single-table reads on a known index, an MDBREADMI transaction is faster.

If your team pulls M3 tables by hand like this, we can put a private assistant on your own servers that answers those questions from M3 data with the query shown.