How to Export Orders to CSV via FTP

Generate a CSV file of orders and upload it to an FTP server automatically.

What This Integration Does

Many back-office systems, 3PLs, and accounting tools still expect a daily CSV drop on an FTP or SFTP server. Rather than logging into your store, exporting, and uploading by hand, this workflow pulls the previous day's orders straight from your e-commerce platform, flattens them into a CSV, and pushes the file to the partner's drop folder on a schedule.

The workflow runs on a schedule (typically nightly), scopes its query to a fixed time window, and writes a uniquely named CSV per run so partners can pick up files without overwriting yesterday's data. Each run is independent and re-runnable - if a partner needs yesterday's drop again, you just rerun with the previous window.

Prerequisites

  • A Shopify connection with read_orders scope, or a WooCommerce connection with read access to orders.
  • An FTP connection configured with host, port, username, and password (or SFTP key).
  • The remote directory path your partner expects files to land in (e.g. /incoming/orders/).
  • An agreed CSV column schema with the partner so the file matches their importer.

Step 1: Schedule Trigger

Drop a Trigger node on the canvas and set its type to Schedule. A daily cadence at 02:00 store-local time works for most partners - it gives the store time to close out the previous day and lands the file before the partner's morning import job. Capture now from the trigger so the rest of the workflow can derive the export window from it.

Step 2: Compute the Export Window

Add a Transform node to set two variables:

  • windowStart - start of yesterday in your store timezone.
  • windowEnd - end of yesterday in your store timezone.

You can use the date connector's start-of and end-of tools with unit: "day" against {{ trigger.now }} minus one day to compute these. Persisting the window as variables keeps the query reproducible if you need to re-run.

Step 3: Fetch Orders

Add a Connector node pointing at shopify and pick the list-orders tool (use woocommerce list-orders if you're on WooCommerce). Configure:

  • created_at_min: {{ windowStart }}
  • created_at_max: {{ windowEnd }}
  • status: any (or filter to paid if your partner only wants paid orders)
  • limit: 250 (the max per page on Shopify)

If you expect more than 250 orders per day, wrap the call in a Loop node that paginates until the response page is empty.

Step 4: Shape the Rows

Add a Transform node to project each order into the flat columns the partner expects. A typical row looks like:

{
  "order_number": "{{ order.name }}",
  "order_date": "{{ order.created_at }}",
  "customer_email": "{{ order.email }}",
  "ship_name": "{{ order.shipping_address.name }}",
  "ship_address1": "{{ order.shipping_address.address1 }}",
  "ship_city": "{{ order.shipping_address.city }}",
  "ship_postcode": "{{ order.shipping_address.zip }}",
  "ship_country": "{{ order.shipping_address.country_code }}",
  "total": "{{ order.total_price }}",
  "currency": "{{ order.currency }}"
}

Loop over order.line_items if your partner needs one row per line item rather than one row per order.

Step 5: Convert to CSV

Add a Connector node pointing at csv and pick the from-json tool. Pass the array of shaped rows. Set includeHeaders to true so the first row carries column names. The output is a UTF-8 CSV string ready for upload.

Step 6: Upload via FTP

Add a Connector node pointing at ftp and pick the upload-file tool. Configure:

  • remotePath: /incoming/orders/orders-{{ windowStart | date "YYYY-MM-DD" }}.csv
  • content: the CSV string from Step 5
  • overwrite: false so a re-run doesn't silently clobber a prior file

Follow with a Condition node checking the upload result. On failure, route to a slack send-message call so on-call notices before the partner does.

Tips

  • Name files with a date stamp - dated filenames make replays safe and let the partner spot a missed day instantly.
  • Validate connectivity first - use the ftp verify-connection tool in a one-shot test workflow before scheduling production drops.
  • Stay under rate limits - Shopify's list-orders is 2 req/sec on the standard plan; a daily window almost always fits in one or two paged calls.

Common Pitfalls

  • Timezone drift - if your store is in UTC but reports in Sydney time, an order placed at 23:30 local can land in the wrong day's file. Pin windowStart and windowEnd to the store timezone, not UTC.
  • Embedded commas and newlines - customer names and addresses often contain them. The csv from-json tool quotes correctly, but a hand-rolled string join will corrupt rows.
  • FTP vs SFTP confusion - the ftp connector supports both, but the port and auth method differ. Confirm with the partner before configuring.
  • Partial uploads - if the workflow fails mid-upload some servers leave a half-file. Upload to a .tmp filename, then use the ftp rename tool to atomically rename to the final name.

Testing

Run the workflow manually with a narrow window (say, the last hour) and inspect the file that lands on the FTP server. Open it in a spreadsheet to confirm column order, quoting, and date formatting all match the partner spec. Once the sample looks right, enable the schedule.

Learn More

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