How to Generate a SmartFreight Consignment From a CSV Shipment Manifest

Build a Spojit workflow that runs on a schedule, downloads a CSV shipment manifest from FTP, loops every row, imports one SmartFreight consignment per shipment, and posts a run summary to Slack.

What This Integration Does

Many warehouses and 3PL systems drop a daily manifest file onto an FTP server: one row per shipment, with sender, receiver, carrier, and freight details. This workflow turns that flat file into real consignments in SmartFreight without anyone copying rows by hand. Each morning the file is collected, parsed, and pushed row by row into SmartFreight using the import-consignment tool, then your team gets a single Slack message confirming how many consignments were created and how many failed.

The workflow is started by a Schedule trigger on a cron expression and timezone you choose. On each run it reads one manifest file from FTP, converts the CSV text to rows, iterates them with a Loop node, and calls SmartFreight once per row. Successes and failures are tallied as the loop runs, and the final counts are sent to Slack. The workflow does not mutate the manifest file or hold state between runs, so each scheduled run is independent: if a run fails partway, you can re-run it, though SmartFreight may already hold consignments created before the failure point (see Common Pitfalls).

Prerequisites

  • An FTP connection in Spojit pointing at the server that holds your manifest file, with read access to the folder. See Adding a New Connection.
  • A SmartFreight connection authorized to import consignments.
  • A Slack connection with permission to post to the channel you want the summary in.
  • A known, stable manifest path and filename pattern on the FTP server (for example /manifests/shipments-today.csv), and knowledge of the exact CSV column headers your file uses.
  • The SmartFreight consignment field names your account expects (sender, receiver, carrier, weight, and similar), so you can map CSV columns onto them.

Step 1: Start the workflow on a Schedule trigger

Add a Trigger node and set its type to Schedule. A Schedule trigger uses a 5-field Unix cron expression plus an IANA timezone, so it fires at a wall-clock time you control. For a weekday 7am pickup, set the cron to 0 7 * * 1-5 and the timezone to your depot's zone, for example Australia/Sydney. The trigger output is {{ scheduledAt }}, the timestamp the run started. A single trigger can hold more than one schedule if you need several pickup times per day.

Step 2: Download the manifest from FTP

Add a Connector node in Direct mode, choose the FTP connector, and select the download-file tool. Set path to the manifest location, for example /manifests/shipments-today.csv, and leave encoding as utf8 since a CSV manifest is text. The tool returns the file contents under data.content along with data.size. Reference the text downstream as {{ ftp_download.data.content }} (rename the node variable to match your own).

If your filename changes each day (for example it includes a date), use the FTP list-directory tool first to list the folder, then pick the file you want before downloading. For a fixed filename, download-file alone is enough.

Step 3: Parse the CSV into rows

Add a Connector node in Direct mode, choose the CSV connector, and select the parse tool. Feed the downloaded text into it as the CSV input:

{
  "csv": "{{ ftp_download.data.content }}",
  "header": true
}

With a header row, each parsed row becomes an object keyed by your column names (for example row.recName, row.recPostcode, row.weightKg). Keep the parsed array in a variable such as {{ csv_parse }} so the loop can iterate it. If you want to skip blank or malformed lines, you can chain the CSV filter tool before the loop.

Step 4: Loop each shipment row

Add a Loop node set to ForEach and point it at the parsed rows, for example {{ csv_parse.data }} (use the exact field your CSV node returns). Inside the loop body each item is available as the current row, for example {{ item }}. Everything you place inside the loop body runs once per shipment. This is where you build the consignment payload and call SmartFreight. For large manifests, keep the loop body lean so each iteration stays fast.

Step 5: Import one SmartFreight consignment per row

Inside the loop body, add a Connector node in Direct mode, choose the SmartFreight connector, and select the import-consignment tool. Its single input is consignment, a JSON object of connote fields covering sender, receiver, carrier, and freight details. Map your CSV columns onto the SmartFreight field names your account uses. A simplified example:

{
  "consignment": {
    "recname": "{{ item.recipientName }}",
    "recadd1": "{{ item.address1 }}",
    "recsuburb": "{{ item.suburb }}",
    "recpostcode": "{{ item.postcode }}",
    "carrier": "{{ item.carrier }}",
    "weight": "{{ item.weightKg }}",
    "items": "{{ item.cartons }}",
    "reference": "{{ item.orderRef }}"
  }
}

The tool returns success and a data object from SmartFreight. Use a small Transform node or the JSON connector to keep a running tally of successes and failures across iterations (for example increment a counter when success is true), so you have totals ready for the summary in the next step. If a row needs judgment to map (inconsistent carrier names, missing fields), consider an Agent mode Connector node instead, but Direct mode is cheaper and predictable for clean manifests.

Step 6: Post the run summary to Slack

After the loop completes, add a Connector node in Direct mode, choose the Slack connector, and select the send-message tool. Set the target channel and compose the body from your tallies and the trigger time:

{
  "channel": "#shipping-ops",
  "text": "SmartFreight manifest run {{ scheduledAt }}: {{ totals.created }} consignments created, {{ totals.failed }} failed out of {{ totals.total }} rows."
}

If you want failures called out by reference number, build a list of failed rows during the loop and include it in the text. You can also use lookup-user-by-email to tag a specific person when failures are above a threshold.

Tips

  • Build the skeleton fast with Miraxa, the intelligent layer across your automation: try the prompt "Build a workflow with a Schedule trigger that downloads a CSV from FTP, loops each row, and imports a SmartFreight consignment per row," then fine-tune field mappings in the properties panel.
  • Run the SmartFreight calculate-rate or cost-comparison tool inside the loop before importing if you want to confirm a carrier or rate per shipment.
  • Keep the SmartFreight field names in one place (a Transform node that builds the consignment object) so a manifest column rename only needs one edit.
  • Set the Schedule timezone explicitly to the depot's zone; do not rely on a default, so cutoff times stay correct across daylight-saving changes.

Common Pitfalls

  • Partial-run duplicates. If a run fails after some rows imported, re-running imports those rows again. Add a unique reference per consignment and use find-consignment to check before importing, or only re-run the rows that failed.
  • Header mismatch. The CSV parse tool keys rows by the actual header text. A renamed or reordered column silently produces empty fields, so validate headers before going live.
  • Wrong encoding. Download the manifest as utf8, not base64; base64 is for binary files and the CSV connector expects text.
  • Empty manifest. If no file is present or the file has no rows, the loop runs zero times and SmartFreight is never called. Add a Condition node after parsing to send a "no shipments today" Slack note rather than a silent run.

Testing

Before scheduling, switch the trigger to Manual and run with a small test manifest of two or three rows placed on the FTP server. Use the execution log to confirm the FTP download returned the expected text, the CSV node produced the right number of rows, and the SmartFreight import-consignment calls returned success: true. Verify the consignments appear in SmartFreight with find-consignment or your SmartFreight portal, then check the Slack summary shows the correct counts. Once the small batch is clean, switch the trigger back to Schedule and enable the workflow.

Learn More

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