How to Sync MarketMan Vendor Catalog Items into a NetSuite Item Master Nightly

Build a scheduled Spojit workflow that pulls your vendor catalog from MarketMan every night, maps categories and units, and upserts each item into the NetSuite item master so your purchasing catalog and your ERP stay aligned.

What This Integration Does

Food-wholesale and multi-site hospitality operators run their purchasing in MarketMan, where every vendor lists the products you can order from them. Finance, however, lives in NetSuite, and the item master there has to match what buyers are actually ordering: same item codes, same descriptions, consistent categories, and clean units of measure. Maintaining that by hand drifts fast as vendors add SKUs, rename products, or change pack sizes. This workflow keeps the NetSuite item master in step with the MarketMan vendor catalog automatically, so a buyer never orders something purchasing knows about but accounting does not.

The workflow runs on a nightly Schedule trigger. On each run it calls MarketMan get-catalog-items to pull the current vendor catalog, runs a Transform to map MarketMan categories and units onto your NetSuite field values, then a Loop iterates the catalog and calls NetSuite upsert-record once per item. Because upsert-record is keyed by external ID, the run is idempotent: new catalog items are created, existing ones are updated in place, and re-running the same night changes nothing. This is deliberately the catalog master sync. It does not move stock counts (that is inventory sync) and it does not move purchase orders (that is order sync); it only keeps the item definitions aligned.

Prerequisites

  • A MarketMan connection in Spojit (API key). See the MarketMan connector article to set it up.
  • A NetSuite connection with permission to read and write item records (create/edit Inventory Item or Non-Inventory Item). See the NetSuite connector article.
  • Your MarketMan buyerGuid (and a vendorGuid if you want to scope the sync to one vendor). You can list these from MarketMan or read them from your account setup.
  • A mapping table you control: MarketMan category names to NetSuite category/class values, and MarketMan units to NetSuite units of measure. Decide which NetSuite record type you write (for example inventoryItem or noninventoryitem) before you build.
  • Agreement on the external ID convention, for example using the MarketMan catalog item code as the NetSuite item external ID so the two systems share one stable key.

Step 1: Add the Schedule trigger

Create a new workflow and set the Trigger node type to Schedule. Add a 5-field Unix cron expression and an IANA timezone so the job runs overnight in your local time. For a 2:00 AM run on Sydney time, use:

Cron:     0 2 * * *
Timezone: Australia/Sydney

The trigger output is { scheduledAt }, which you can reference later as {{ trigger.scheduledAt }} for logging. A single Schedule trigger can hold multiple schedules if you want to run the sync more than once a day.

Step 2: Pull the vendor catalog from MarketMan

Add a Connector node in Direct mode on the MarketMan connector and select the get-catalog-items tool. Map the inputs:

  • buyerGuid: your buyer GUID (leave blank to use the connection default).
  • vendorGuid: set this only if you want a single-vendor catalog; leave blank to pull every vendor.

Set the node's output variable to catalog. Direct mode is the right choice here because it is a single, predictable call with no AI cost. The catalog rows arrive under the result envelope, which you will reference as {{ catalog.data }} in the next step (confirm the exact array path from the run preview).

Step 3: Map categories and units with a Transform

Add a Transform node to reshape each raw MarketMan catalog row into the exact field shape your NetSuite item record expects. This is where you translate MarketMan category names and unit labels into the values NetSuite stores, and where you set the external ID from the catalog item code. Produce a clean array of item payloads, for example:

{
  "items": [
    {
      "externalId": "{{ row.CatalogItemCode }}",
      "itemId": "{{ row.Name }}",
      "purchaseDescription": "{{ row.Description }}",
      "category": "{{ mapCategory(row.Category) }}",
      "purchaseUnit": "{{ mapUnit(row.Unit) }}",
      "vendorName": "{{ row.VendorName }}"
    }
  ]
}

If your category and unit mapping is more than a simple rename, add a Connector node on the code connector with execute-javascript to apply lookup tables, then feed its output into the Transform. Save the mapped array to a variable named mapped. Keep the mapping data inside the workflow (or a small JSON lookup) so a vendor adding an unexpected category never silently writes a blank field into NetSuite.

Step 4: Loop over the mapped catalog

Add a Loop node in ForEach mode and point it at {{ mapped.items }}. Each iteration exposes the current row as the loop item (for example {{ item }}). The body of this loop will hold the NetSuite write in the next step. Looping one item at a time keeps each upsert independent, so a single bad row fails only that iteration rather than the whole catalog, and the execution log shows exactly which item codes succeeded.

Step 5: Upsert each item into NetSuite

Inside the Loop body, add a Connector node in Direct mode on the NetSuite connector and select the upsert-record tool. Map the inputs:

  • recordType: your item record type, for example inventoryItem.
  • externalId: {{ item.externalId }} (the MarketMan catalog item code).
  • body: the mapped record payload.

A representative body payload:

{
  "itemId": "{{ item.itemId }}",
  "purchaseDescription": "{{ item.purchaseDescription }}",
  "category": "{{ item.category }}",
  "purchaseUnit": "{{ item.purchaseUnit }}"
}

Because upsert-record is keyed by external ID, NetSuite creates the item the first night it sees a code and updates the same record on every night after. There is no separate "create vs update" branch to maintain, which is what makes the nightly run safe to repeat. Use the exact NetSuite field names for your account; confirm them with get-record-metadata on your item record type if you are unsure.

Step 6: Send a summary email

After the Loop, add a Send Email node so the purchasing team gets a nightly confirmation. Set Recipients, a templated Subject such as Catalog sync complete: {{ mapped.items.length }} items, and a body that lists counts. Set If sending fails to Continue anyway so a mail hiccup never marks the sync itself as failed. For richer alerting you can instead route the summary to a channel with the Slack connector send-message tool.

Tips

  • Scope your first builds with vendorGuid so you sync one vendor's catalog before opening it up to all vendors.
  • Run the nightly cron in a low-traffic window (early morning) and in a timezone that matches your accounting close, so the item master is current before buyers start the day.
  • Keep the category and unit mapping in one place. When a vendor introduces a new category, you update the lookup once rather than chasing it across records.
  • Ask Miraxa, the intelligent layer across your automation, to scaffold the skeleton: "Build a workflow with a Schedule trigger that calls MarketMan get-catalog-items, a Transform, then a Loop that calls NetSuite upsert-record." Then fine-tune field mappings in the properties panel.

Common Pitfalls

  • External ID drift. If you key on a value that changes (a name instead of the catalog item code), the next run creates a duplicate item instead of updating the existing one. Always key upsert-record on a stable MarketMan code.
  • Unmapped categories or units. A MarketMan value with no entry in your lookup can write a blank or invalid NetSuite field. Add a default and log unmapped values so you can extend the mapping.
  • Wrong record type. Writing an inventory body to a non-inventory record type (or vice versa) will be rejected by NetSuite. Confirm the type with get-record-metadata before going live.
  • Large catalogs and rate limits. A big catalog means many sequential upserts. If you hit NetSuite throttling, slow the Loop or split the sync by vendor across separate schedules rather than firing everything at once.

Testing

Before enabling the schedule, set vendorGuid to a single small vendor and run the workflow with the Run button. Inspect the execution log: confirm get-catalog-items returned rows, that the Transform produced a clean mapped.items array, and that the Loop called upsert-record once per item. Open one of those items in NetSuite and verify the description, category, and unit are correct. Run the workflow a second time and confirm no duplicates appear (the same external IDs update in place). Once one vendor looks right, widen the scope and turn the Schedule trigger on.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.