Mechanic
đŸ“Ŗ Shopify REST Deprecation
  • â›Šī¸Introduction
  • 🤓Hire a Mechanic developer
  • đŸ’¯status.mechanic.dev
  • đŸ“ŖShopify is deprecating the REST API
  • 🙋"I need something custom!"
  • 🧑‍đŸ’ģ"I need help with my custom task!"
  • 🤖"I need help with my AI-written task!"
  • Resources
    • âŦ‡ī¸Install Mechanic
    • 🧑‍đŸ’ģTask library
      • Contributing
      • Requesting
    • 🚀Slack community
    • 🤝Partner directory
    • 🧠Tutorials
      • Video walkthroughs
        • Auto-tag orders by originating staff member
        • Maintain a tag for orders processed today
        • Auto-tag orders with their tracking numbers
        • Sync inventory for shared SKUs
        • Auto-tag products when their SKU(s) change
        • Auto-publish new products
        • Email a report of customers who haven't ordered in X days
        • Upgrading a Mechanic task: Adding a time delay
        • Email the customer when tracking numbers are added to their order
        • Adding an optional time delay to your Mechanic task
        • Delete all orders
        • Send an email when a specific product is shipped
        • Send recurring reminders about unpaid orders
        • Send an email when a product's price goes below its cost
        • Auto-tag customers by sales channel
        • Creating products in bulk
      • Creating a Mechanic webhook
      • Practicing writing tasks
      • Triggering tasks from a contact form
      • Creating scheduled CSV feeds
      • Fetching data from a shared Google sheet
    • 🏆Converting tasks from Shopify REST to GraphQL
      • Conversion: Single resource lookups
      • Conversion: Resource loops to paginated queries
      • Conversion: Connections from a resource
      • Conversion: Metafield lookups from a resource
      • Conversion: Resource lookups in task option fields
  • Core Concepts
    • Events
      • Topics
      • Parent and child events
    • Tasks
      • Subscriptions
      • Code
        • Environment variables
        • Action objects
        • Error objects
        • Log objects
      • Options
        • Custom validation
      • Previews
        • Defining preview events
        • Stub data
      • Shopify API version
      • Advanced settings
        • Documentation
        • JavaScript
        • Perform action runs in sequence
      • Import and export
      • User Form
    • Actions
      • Cache
      • Echo
      • Email
      • Event
      • Files
      • Flow
      • FTP
      • Google Drive
      • Google Sheets
      • HTTP
      • Integrations
        • Report Toaster
      • Shopify
      • File generators
        • Base64
        • PDF
        • Plaintext
        • URL
        • ZIP
    • Runs
      • Scheduling
      • Concurrency
      • Ordering
      • Retries
    • Interacting with Shopify
      • Responding to events
        • Reconciling missing events
      • Reading data
        • âš ī¸Liquid objects
        • 🏆GraphQL in Liquid
        • Bulk operations
        • The Shopify action
      • Writing data
      • Shopify admin action links
      • API rate limit
      • API versions
  • Platform
    • 🔆Policies
      • Data
      • Plans
      • Pricing
      • Privacy
    • Cache
      • Cache endpoints
    • Email
      • Receiving email
      • Custom email addresses
      • DMARC
      • Email templates
    • Error handling
    • Events
      • Event topics
      • Event filters
    • GraphQL
      • Basics
        • Shopify Admin API GraphiQL explorer
        • Queries
        • Mutations
        • Pagination
      • Bulk operations
    • Integrations
      • Appstle Subscriptions
      • Google Drive and Google Sheets
      • Judge.me
      • Locksmith
      • Report Toaster
      • Shopify Flow
      • Run links
    • Liquid
      • Basics
        • Syntax
        • Data types
        • Variables
        • Comments
        • Filters
        • Operators
        • Control flow
          • Condition
          • Iteration
        • Whitespace
      • Liquid console
      • Mechanic filters
        • Deprecated filters
      • Mechanic keyword literals
        • array
        • hash
        • newline
      • Mechanic objects
        • Action object
        • Cache object
        • Event object
        • Options object
        • Task object
        • âš ī¸Shopify REST Admin API
          • đŸšĢArticle object
          • đŸšĢBlog object
          • đŸšĢCollection object
          • đŸšĢCustomer object
          • đŸšĢDiscount code object
          • đŸšĢDispute object
          • đŸšĢDraft order object
          • đŸšĢFulfillment object
          • đŸšĢFulfillment order object
          • đŸšĢFulfillment event object
          • đŸšĢGift card object
          • đŸšĢInventory item object
          • đŸšĢInventory level object
          • đŸšĢLine item object
          • đŸšĢLocation object
          • đŸšĢMetafields
            • Metafield object
            • Metafield representation object
            • Metafield collection object
          • đŸšĢOrder object
          • đŸšĢOrder risk object
          • đŸšĢPrice rule object
          • đŸšĢProduct object
          • đŸšĢProduct image object
          • đŸšĢRefund object
          • đŸšĢShipping zone object
          • đŸšĢShop object
          • đŸšĢTheme object
          • đŸšĢTheme asset object
          • đŸšĢTransaction object
          • đŸšĢVariant object
      • Mechanic tags
        • liquid
        • action
        • assign
        • error
        • log
      • Mechanic code snippets
    • Shopify
      • Custom authentication
      • "Read all orders"
    • Webhooks
  • Techniques
    • Preventing action loops
    • Writing a high-quality task
    • Tagging Shopify resources
    • Debouncing events
    • Responding to action results
    • Working with external APIs
      • JSON Web Signatures
      • AWS request signatures
    • Finding a resource ID
    • Migrating templates from Shopify to Mechanic
    • Securing Mechanic webhooks
    • Monitoring Mechanic
  • FAQ
    • The app isn't loading. What do I do?
    • How do I stop a large batch of runs?
    • A Shopify event is missing. Where is it?
    • Does Mechanic have an affiliate program?
    • Can non-owners install Mechanic?
    • Can I replace Shopify's order emails with Mechanic?
    • Can I manually set Shopify permissions for Mechanic?
    • Does my theme need to be updated for Mechanic?
    • Do you have a plan for development stores?
    • Why don't I see any events in my task's activity?
    • Can I read data back from my webhook submission?
    • My task added a tag, but now the tag is missing – why?
    • How do I add an unsubscribe link to my emails?
    • How do I send images with my emails?
    • Can I re-send order confirmation emails with Mechanic?
    • Why am I seeing a different price than on the app store?
    • Do you have a Partner-friendly plan?
    • Why are my tasks delayed or not running?
    • My task is failing because of a permissions problem. Why?
    • How do I preview email attachments?
    • Can I query external APIs?
    • Why can't I access the Shopify API during preview mode?
    • How do marketing preferences work with Mechanic?
    • Can I send data to Google Sheets?
    • What's possible with timeline comments?
    • I'm getting a "query param length is too long" error when using GraphQL.
    • Can my Mechanic concurrency limit be raised?
    • What IP address does Mechanic use?
    • Can Mechanic read or manage customer subscriptions?
    • Why is everything harder now?
    • Can task content be translated into multiple languages?
    • Can I add a time delay to my task?
    • Can I add another store to my existing Mechanic subscription?
    • How can I reduce memory usage of my task?
    • How do I connect PayPal to Shopify with Mechanic?
    • How do I add a Shopify access scope to my task?
    • Can I have my Mechanic data retained for more (or less) than 15 days?
Powered by GitBook

Important Updates

  • đŸ“Ŗ Shopify REST Deprecation
On this page
  • Options
  • General options
  • FTP options
  • FTPS options
  • SFTP options
  • User authentication
  • Uploads and downloads
  • Result
  • Testing
  • Example

Was this helpful?

Edit on GitHub
Export as PDF
  1. Core Concepts
  2. Actions

FTP

Upload and download files via FTP, FTPS, or SFTP.

PreviousFlowNextGoogle Drive

Last updated 5 months ago

Was this helpful?

The FTP action can upload and download files via , , or . The files to be uploaded are evaluated using . Downloaded file data is available either as an UTF-8 string, or as a base64-encoded string, and can be used in followup task runs via .

A connecting service like can be used to relay these uploads on to other cloud locations, like Dropbox, Google Drive, and Amazon S3.

A single FTP action may download a maximum of 20MB of data, across all downloaded files.

Options

General options

Option
Type
Notes

protocol

"ftp", "ftps", or "sftp"

The protocol to use for connection; inferred if omitted

host

String, required

The hostname or IP address of the destination server

port

Number, optional

The server port to connect to

user

String, required

The username for authentication

password

String, optional

The password for authentication

uploads

Hash, optional

downloads

Array, optional

File path strings (relative or absolute) to download

FTP options

Option
Type
Notes

mode

String, optional

May be set to "ascii"; defaults to "binary"

FTPS options

Option
Type
Notes

verify

Boolean, optional

May be set to false to ignore SSL certificate errors

SFTP options

Option
Type
Notes

private_key_pem

String, optional

A complete PEM-formatted private key for authentication

verify

Boolean, optional

May be set to true in combination with "known_hosts" to validate the host

known_hosts

String, optional

User authentication

The user option is always required.

When connecting to an FTP or FTPS server, authenticate with the password option.

When connecting to an SFTP server, authenticate using either password or private_key_pem, or both. PEM certificates may be given directly in the task code:

{% capture private_key_pem %}
-----BEGIN OPENSSH PRIVATE KEY-----
l0UGrDQWWbOpUsLENHwD5ya478pmRXarmDj5Wh31B54nmuq7be4ZKD5eh9nEV42JCl4mX6
...
pZ/WFoT82brhooSfJDue14C0Y=
-----END OPENSSH PRIVATE KEY-----
{% endcapture %}

{% action "ftp" %}
  {
    "host": "example.com",
    "port": 22,
    "user": "sftp_user",
    "private_key_pem": {{ private_key_pem | json }}
    "uploads": {
      "success.txt": "hooray!"
    }
  }
{% endaction %}

Uploads and downloads

Both uploads and downloads allow the task author to define file paths. If only the filename is given (e.g. "sample.pdf"), the file will be resolved in the home directory of the user. If a relative path (e.g. "subdirectory/sample.pdf") or absolute path (e.g. "/tmp/sample.pdf") is given, it will be respected accordingly.

Each individual file operation (i.e. each upload or download) will be attempted a maximum of 3 times within the FTP/FTPS/SFTP session, retrying if an error occurs during upload or download.

Example

This example action results in (a) an upload to an absolute path, starting from the server root, (b) an upload to a nested directory within the user's home folder, and (c) an upload to a nested directory in another user's home folder (which may fail, depending on filesystem permissions).

{% action "ftp" %}
  {
    ...
    "uploads": {
      "/absolute/path/to/success.txt": "hooray!",
      "relative/path/to/success.txt": "hooray!",
      "../another/relative/path/to/success.txt": "hooray!"
    }
  }
{% endaction %}

Result

In Mechanic, actions are performed after their originating task run concludes. Actions are not performed inline during the task's Liquid rendering.

To inspect and respond to the results of an HTTP action, add a task subscription to mechanic/actions/perform, allowing the action to re-invoke the task with the action result data.

{
  "log": "connect: ftp.couchdrop.io, 21\n< 220 Couchdrop FTPD\n> USER ********\n< 331 Username ok, send password.\n> PASS ********\n< 230 Welcome ********\n> TYPE I\n< 200 Type set to: Binary.\n> TYPE I\n< 200 Type set to: Binary.\n> PASV\n< 227 Entering passive mode (178,128,9,71,234,153).\n> STOR journal.txt\n< 125 Data connection already open. Transfer starting.\n< 226 Transfer complete.\n> TYPE I\n< 200 Type set to: Binary.\n> TYPE I\n< 200 Type set to: Binary.\n> PASV\n< 227 Entering passive mode (178,128,9,71,234,98).\n> STOR table.csv\n< 125 Data connection already open. Transfer starting.\n< 226 Transfer complete.\n> TYPE I\n< 200 Type set to: Binary.\n> TYPE I\n< 200 Type set to: Binary.\n> PASV\n< 227 Entering passive mode (178,128,9,71,234,135).\n> STOR invoice.pdf\n< 125 Data connection already open. Transfer starting.\n< 226 Transfer complete.\n> TYPE I\n< 200 Type set to: Binary.\n> TYPE I\n< 200 Type set to: Binary.\n> PASV\n< 227 Entering passive mode (178,128,9,71,234,101).\n> STOR secure.zip\n< 125 Data connection already open. Transfer starting.\n< 226 Transfer complete.\n> TYPE I\n< 200 Type set to: Binary.\n> TYPE I\n< 200 Type set to: Binary.\n> PASV\n< 227 Entering passive mode (178,128,9,71,234,100).\n> STOR external.jpg\n< 125 Data connection already open. Transfer starting.\n< 226 Transfer complete.\n> TYPE I\n< 200 Type set to: Binary.\n> TYPE I\n< 200 Type set to: Binary.\n> PASV\n< 227 Entering passive mode (178,128,9,71,234,183).\n> RETR journal.txt\n< 125 Data connection already open. Transfer starting.\n< 226 Transfer complete.\n> TYPE I\n< 200 Type set to: Binary.\n> TYPE I\n< 200 Type set to: Binary.\n> PASV\n< 227 Entering passive mode (178,128,9,71,234,149).\n> RETR table.csv\n< 125 Data connection already open. Transfer starting.\n< 226 Transfer complete.\n> TYPE I\n< 200 Type set to: Binary.\n",
  "uploads": {
    "invoice.pdf": {
      "size": 7232
    },
    "secure.zip": {
      "size": 205
    },
    "external.jpg": {
      "size": 27661
    }
  },
  "downloads": {
    "journal.txt": {
      "size": 12,
      "data": "hello world!",
      "data_base64": "aGVsbG8gd29ybGQh"
    },
    "table.csv": {
      "size": 27,
      "data": "Title,SKU\nRed T-Shirt,TEE-R",
      "data_base64": "VGl0bGUsU0tVClJlZCBULVNoaXJ0LFRFRS1S"
    }
  }
}

Testing

Uploads are processed before downloads; it can be useful to test by uploading a file, and then immediately downloading it again:

{% action "ftp" %}
  {
    "host": "ftp.couchdrop.io",
    ...
    "uploads": {
      "hello-world.txt": "hello world!"
    },
    "downloads": [
      "hello-world.txt"
    ]
  }
{% endaction %}

Example

This task compiles all SKUs with their titles and prices, and uploads it as a CSV every night or on demand.

mechanic/scheduler/daily
mechanic/user/trigger
{% assign csv_rows = array %}

{% assign header = "SKU,Title,Price" | split: "," %}
{% assign csv_rows[0] = header %}

{% for product in shop.products %}
  {% for variant in product.variants %}
    {% assign title = variant.title %}
    {% if title == "Default Title" %}
      {% assign title = product.title %}
    {% endif %}

    {% assign row = array %}
    {% assign row[row.size] = variant.sku %}
    {% assign row[row.size] = title %}
    {% assign row[row.size] = variant.price %}

    {% assign csv_rows[csv_rows.size] = row %}
  {% endfor %}
{% endfor %}

{% capture filename %}product-export-{{ "now" | date: "%Y-%m-%d" }}.csv{% endcapture %}

{% action "ftp" %}
  {
    "host": "example.com",
    "port": 21,
    "user": "anonymous",
    "password": null,
    "uploads": {
      {{ filename | json }}: {{ csv_rows | csv | json }}
    }
  }
{% endaction %}

An object whose keys are file paths (relative or absolute), and whose values are

An sshd-compatible known_hosts file (, )

Learn more:

An FTP action returns the following data structure, most useful in combination with mechanic/actions/perform (see ):

Note that each uploaded and downloaded file is keyed by the path provided for that file in the action's options. Downloaded file data is available as a UTF-8 string; for binary data that cannot be represented in UTF-8, use the base64-encoded version, possibly in concert with the filter.

If a server is unavailable for testing, consider using , with . This is a (nearly) configuration-free avenue for testing, using my.couchdrop.io for FTP, FTPS, or SFTP.

Alternatively, can be used to create a public tunnel to a local FTP or SSH server. By running ngrok tcp 22 (adjusting for the appropriate local port), ngrok will generate a temporary public host and port that's appropriate for use while testing.

FTP
FTPS
SFTP
file generators
mechanic/actions/perform
Couchdrop
Responding to action results
Responding to action results
decode_base64
Couchdrop
their hosted storage service
ngrok
file generators
docs
helpful article