Agent skills › manifold-import
Download the skill · SKILL.md ·
over MCP, the prompt manifold-import
Importing data into Manifold
You are bringing a merchant's records into Manifold in bulk. Every row you submit becomes an ordinary command to the part of Manifold that owns it, sent as the merchant you are connected as. So Manifold enforces its own rules on every row: a duplicate SKU, an oversell, a receipt against an unapproved order. What you can import is exactly what the merchant could do by hand.
The full reference, with every field, retry behaviour and limit, is docs/import-export.md in the Manifold repository and on the docs site. This skill is the working procedure.
What you need
- The Manifold connector in this client. If it is not connected, follow the manifold-onboarding skill first.
- The data. A file the merchant shares with you, a table they paste, or a list they dictate. You cannot upload a file to Manifold over the connector. You read it and submit its rows. A merchant who would rather upload the file themselves does it in the admin at Import & export (§8).
Never
- Never ask for, read out or type a password, an API key or any other credential, even if one appears in the merchant's file. Leave that column out and tell them it was there.
- Never invent data: no made-up SKUs, prices, costs, quantities, emails or ids. A blank you cannot fill stays blank, or you ask.
- Never apply anything the merchant has not seen. Stage, show, then commit (§5).
- Never re-submit a stock adjustment file. Adjustments are the one import that applies again when loaded twice (§7).
- Never split one document (a purchase order, a sales order, a refund, a product's variants, a kit's components) across two submissions (§4).
1. Reaching the tools
Every tool named here is served. manifold_find_tools searches them, manifold_describe_tool shows one's inputs, and manifold_call_read / manifold_call_write run one by name. The import tools:
| Tool | Does |
|---|---|
| imports_list_targets | Lists what can be imported and every field each target accepts. This is the live list; trust it over this page. |
| imports_submit_rows | Submits rows as JSON: the way you import. |
| imports_preview_job | Shows a job's staged rows, the target it is read as, and every target ranked by fit. |
| imports_change_target | Reads a staged job as another target. |
| imports_map_columns | Sets which column feeds which field. Only needed for a job the merchant uploaded. |
| imports_commit_job | Runs a staged job. |
| imports_get_job | A job's status and counters. |
| imports_list_failures | Every rejected row, with the field and the reason. |
| imports_list_mappings, imports_save_mapping | Saved column mappings, for files the merchant uploads again and again. |
| imports_preview_export | Reads a page of what an export would contain, filtered and narrowed to chosen columns. |
| manifold_wait | Holds one call open until a job finishes, instead of you polling. |
2. Work out what the data is
Read the first rows and the headers, and decide which target each sheet is. One sheet is one target; a workbook with tabs is several imports.
| The data holds… | Target | One row is… |
|---|---|---|
| SKUs, names, opening quantities (one location) | inventory.item | a SKU, once: a second row for it is refused |
| Products with sizes or colours over SKUs | catalog.product | a variant, grouped by productKey |
| Kits or bundles and their parts | catalog.composite | a component, grouped by the kit sku |
| Prices per price list | catalog.price | a SKU's price in one catalog |
| Warehouses, shops, 3PLs | inventory.location | a location |
| Suppliers or business customers | crm.company | a company |
| People: customers, contacts | crm.person | a person |
| Purchase orders | purchasing.po | a line, grouped by reference |
| Deliveries against approved POs | purchasing.receipt | a line, grouped by receiptId |
| Sales orders | fulfillment.order | a line, grouped by reference |
| Order history (shipped, cancelled, refunded) | fulfillment.historical-order | a line, grouped by externalNumber and source |
| Picked parcels | fulfillment.pick | a line, grouped by order + shipment |
| Courier manifests (tracking numbers) | fulfillment.ship | a parcel |
| Refunds | fulfillment.refund | a line, grouped by reference |
| Stock corrections | inventory.adjustment | a movement |
If you are unsure, submit with run: false (§5) and read imports_preview_job: its candidates rank every target by how well the columns fit, with matched (columns recognised) and requiredMissing (required fields with no column). Tell the merchant what you think the sheet is and why, and let them correct you.
3. Load in order
Each target needs what the ones before it create. For a full setup, go in this order and finish each before the next:
inventory.location: only the sites beyondMain, which exists already.inventory.item: the SKU master, one row per SKU. Serial- or batch-tracked SKUs go in at quantity 0, and their stock arrives by receipt. A SKU held at several locations goes in once; its quantity per location is a count on the opening stocktake (inventory_record_stocktake_counts), which sets the figure and is safe to save again.catalog.product, thencatalog.composite.catalog.price. The catalogs themselves are not importable: find them withcatalog_list_catalogs, or create one withcatalog_create_catalogafter asking.crm.company,crm.person.purchasing.pocreates drafts. A receipt needs an approved PO: the merchant approves in the admin, or you callpurchasing_authorise_powith their go-ahead. Thenpurchasing.receipt, naming each PO by thepo_…id frompurchasing_list_pos.fulfillment.order, then picks, shipments and refunds, naming orders, parcels and lines by the ids fulfillment issued (fulfillment_get_order). Orders long since finished arefulfillment.historical-orderinstead: kept for the record, holding no stock.
inventory.adjustment can run any time after the items exist.
4. Shape the rows
imports_submit_rows takes:
targetheaders: the target's field names, exactly asimports_list_targetsgives them (unitCostCents, not "Unit cost"). Only columns you have data for. Every required field must be there.rows: arrays of cells in header order: a string, a number, true/false, or null for blank.reference: your key for this batch (§5).run: false to stage for review, true to run at once.filename: optional, how the job is named in the admin.
Translate the merchant's data:
- Money is whole cents: 12.50 becomes
1250. A cost or price column in dollars is converted, never copied. - SKUs are uppercased by Manifold. Keep them exactly as the source spells them otherwise.
- Yes/no columns take true/false, yes/no, y/n or 1/0.
- Dates are ISO 8601 (
2026-11-30). - Lists (tags, roles, serial numbers) are one cell, separated by
;. - Choices must be one of the field's options (
imports_list_targetslists them):fifo,active,customer;supplier. Map the source's words onto them, and ask when the mapping is not obvious. - Ids of things already in Manifold are the ids Manifold shows (
loc_…,cat_…,prd_…,po_…,ord_…,shp_…,lin_…), looked up with the list tools. The merchant's own document numbers go inreferencecolumns. - Grouped targets: a document's rows sit together, one after another. Its document-level columns (supplier, catalog, title, refund amount) are read from its first row. For these targets, keep each submission to at most 500 rows, whole documents only: rows are grouped 500 at a time, and a document cut across that boundary loses its later lines.
At most 5,000 rows per submission. Page larger sets into several submissions under distinct references, each holding whole documents only.
5. Stage, show, commit
- Mint a
referencefor the batch before the first call, and reuse it on any retry:<what>-<date>-<n>, e.g.items-2026-10-06-1. A second submission with the same reference changes nothing and answers with the job already staged. A fresh reference on a retry is how data gets imported twice. - Stage it:
imports_submit_rowswithrun: false. A 422 means a header is not a field, or a required field is missing. Fix the headers and resubmit under the same reference. - Show the merchant:
imports_preview_jobshows the first staged rows. Summarise what will happen ("312 SKUs, 40 with opening stock at Main; 3 rows have no name") and wait for their go-ahead. - Run it:
imports_commit_jobwith the job id. It answers at once and the job runs in the background, one job at a time per merchant. - Wait:
manifold_waitwithname: "imports_get_job",arguments: { "jobId": … },until: ["completed", "failed"]. Call it again if it answersreached: false.
For a small, obvious import the merchant has already approved row by row, run: true stages and runs in one call.
Long imports: a job runs with the access the merchant had when it was committed, and that access lasts 15 minutes. Split very large loads into several jobs, each committed when the last has finished.
6. Read the result
imports_get_job reports progress: applied, failed, and skipped (the header row). completed means every row was tried. Some may still have failed. failed means the job itself stopped, and its reason says why.
For failures, imports_list_failures gives each rejected row's number, field and reason in plain words: "SKU TEE-S already exists", "only 3 on hand, 5 requested", "purchase order is draft, not authorised", "TEE-XL is not an inventory item — import it as an item first". Group them, explain them to the merchant, fix what can be fixed, and submit only the corrected rows under a new reference. Row numbers count from the header (row 0), so row 1 is the first data row.
7. What is safe to submit again
| Target | Loaded twice… |
|---|---|
| inventory.item, catalog.product, catalog.composite, inventory.location | refused as duplicates: safe |
| catalog.price | sets the same price: safe |
| purchasing.po, fulfillment.order, fulfillment.refund | recognised by their reference: safe |
| fulfillment.ship, fulfillment.pick | recognised by the parcel: safe |
| fulfillment.historical-order | recorded by content: the same file changes nothing, a corrected one replaces the order: safe |
| crm.company, crm.person | safe only with a reference column: give every row the source system's id. Without one, a company is created twice (a person is refused by email). |
| purchasing.receipt | safe only with a receiptId (rcpt_ plus a uuid you mint per delivery). Without one, stock is received again. |
| inventory.adjustment | applied again. Never resubmit; correct with a new, opposite adjustment. |
8. When the merchant uploads the file themselves
Send them to Import & export in the admin (https://admin.getmanifold.io/import). They choose the file. Manifold recognises what it is from its columns and says so ("Recognised as Products and variants — 7 of 7 columns recognised"). They can switch it to another entity from the same picker, check each column's mapping, see any cell that would be rejected flagged in red, and start the import. You can follow along: their job appears in imports_get_job and imports_list_failures like any other.
9. Check the result
Read a sample back with the owning list tools (inventory_list_items, catalog_list_products, crm_list_companies, crm_list_people, purchasing_list_pos, fulfillment_list_orders), or page through what an export would hold with imports_preview_export (columns and rules narrow it, offset pages it). Then tell the merchant what is in, what was rejected and why, and what is left for them to do. Every change is on the activity trail as made by them.