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

> Source: https://netray.co/tools/infor-m3-exportmi-select-query-generator
> Publisher: Netray (netray.co), AI and integration engineering for ERP and manufacturing systems.
> Section: Free Tools

## Short answer

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.

## Category

developer

## Erp

Infor M3

## Audience

- M3 developer
- Integration consultant
- M3 technical consultant
- Data analyst

## Tool

**Kind:** template

**Output:** code

**Language:** http

**Fields:**

#### M3 BE host

**Key:** host

**Type:** text

**Default:** m3be.acme.local

#### m3api-rest port

**Key:** port

**Type:** text

**Default:** 21108

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

#### M3 user

**Key:** user

**Type:** text

**Default:** M3SRVINT

#### Company (CONO, set on the session)

**Key:** cono

**Type:** text

**Default:** 100

#### Table, optionally with index suffix

**Key:** table

**Type:** text

**Default:** MITMAS

**Help:** MITMAS uses index 00. MITMAS80 would use index 80.

#### Columns (comma separated, with table prefix)

**Key:** columns

**Type:** text

**Default:** MMITNO,MMITDS,MMSTAT

#### Where filter (no company field)

**Key:** where

**Type:** text

**Default:** MMSTAT = '20'

#### Separator (SEPC)

**Key:** sepc

**Type:** text

**Default:** ;

#### Header record (HDRS)

**Key:** hdrs

**Type:** select

**Options:**

- 1
- 0

**Default:** 1

#### Max records per call

**Key:** maxrecs

**Type:** number

**Default:** 10000

#### Key field for paging (leading key of the index)

**Key:** key_field

**Type:** text

**Default:** MMITNO

#### Last key value from previous page

**Key:** last_value

**Type:** text

**Default:** A-10450

**Blocks:**

#### Decoded QERY (first page)

**Body:** {{columns}} from {{table}} where {{where}}

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

**Body:** GET https://{{host}}:{{port}}/m3api-rest/execute/EXPORTMI/Select;cono={{cono}};maxrecs={{maxrecs}}?SEPC=<encoded {{sepc}}>&HDRS={{hdrs}}&QERY=<url-encoded query above>
Authorization: Basic <base64 of {{user}}:password>
Accept: application/json

#### curl (encodes the parameters for you)

**Body:** curl -s -G -u "{{user}}" -H "Accept: application/json" \
  "https://{{host}}:{{port}}/m3api-rest/execute/EXPORTMI/Select;cono={{cono}};maxrecs={{maxrecs}}" \
  --data-urlencode "SEPC={{sepc}}" \
  --data-urlencode "HDRS={{hdrs}}" \
  --data-urlencode "QERY={{columns}} from {{table}} where {{where}}"

#### Next page by key range (decoded QERY)

**Body:** {{columns}} from {{table}} where {{where}} and {{key_field}} > '{{last_value}}'

#### Python: page through the whole table by key range

**Body:** import os
import requests

BASE = 'https://{{host}}:{{port}}/m3api-rest/execute/EXPORTMI/Select;cono={{cono}};maxrecs={{maxrecs}}'
COLUMNS = '{{columns}}'
KEY = '{{key_field}}'
SEP = '{{sepc}}'
PAGE = {{maxrecs}}

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

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

rows = []
last = ''
while True:
    q = COLUMNS + ' from {{table}} where {{where}}'
    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('{{table}}_export.csv', 'w', encoding='utf-8') as f:
    f.write(SEP.join(cols) + '\n')
    for line in rows:
        f.write(line + '\n')

**Notes:** 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.

## Content

**Intro:** 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.

**Sections:**

#### How to use it

**Body:** 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.

**Bullets:**

- 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

**Body:** 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

**Body:** 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

**Body:** 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.

**Cta:** 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.

**Faq:**

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

**Answer:** 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?

**Answer:** 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?

**Answer:** 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?

**Answer:** 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.

## Search terms

infor m3 table, infor m3 api pagination, infor m3 rest api, EXPORTMI Select, EXPORTMI QERY SEPC HDRS, m3api-rest execute EXPORTMI, M3 extract table data API, EXPORTMI 10000 records

---
Talk to an engineer: https://netray.co/contact?intent=erp_ai | Machine catalog: https://netray.co/agent/catalog.json
