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
  • Configuration
  • Event data mode
  • Requests
  • File uploads
  • Client-specific endpoints
  • Examples
  • Responses
  • Webhook request ID
  • Retrieving run results

Was this helpful?

Edit on GitHub
Export as PDF
  1. Platform

Webhooks

Previous"Read all orders"NextPreventing action loops

Last updated 12 days ago

Was this helpful?

A Mechanic webhook allows data to be submitted directly to Mechanic, resulting in a new having a particular topic, containing the submitted data. Webhooks are called with simple HTTP POST requests, which means they can be called from any programming language, and from many applications.

Mechanic's webhook API includes CORS support for all origins, making these requests available for use in online user experiences.

This article is an introduction to webhooks. To get started quickly, see .

Tools like () can be useful for exercising Mechanic webhooks without code, for verifying their behavior.

Configuration

  • Name — Something to remember this webhook by ✨

  • Event data mode — Either "Auto" or "Full request"; see below

  • Webhook URL — A unique, permanent, webhook-specific URL, supplied by Mechanic after creating the webhook

Event data mode

Each webhook has a choice of modes used to translate request data into event data.

Changing a webhook's event data mode takes effect immediately for all incoming requests. It does not apply retroactively, i.e. it has no impact on webhook events that were received prior to the change.

Auto (default)

In "Auto" mode, event data is the result of merging an interpreted hash of parameters from the request body with an interpreted hash of parameters from the request query string.

If no parameters from the request body are found, or if parsing the request body fails for any reason, event data is set to parameters from the request query string.

If no structured parameters are found from either the request body or the request query string, event data is set to the request body in string form. If the string is blank (i.e. zero-length or consisting only of whitespace), event data is set to null.

Full request

In "Full request" mode, event data is set to a hash with the following keys:

Key
Type
Notes

body_base64

Base64-encoded string

The raw request body, encoded in base64

body

Hash or null

The interpreted set of structured parameters from the request body, or null if parsing fails for any reason

client_ip

String

The IP address of the requesting client

headers

Hash

Represents the request headers, keyed by lowercased header names, containing arrays of string values (âš ī¸ see warning below)

mime_type

String or null

The MIME type of the request as interpreted from the content-type request header, or null if that header was not found

query_string

String or null

Contains everything after the "?" character in the request URL, or null if no such value was found

query

Hash or null

Contains the interpreted set of structured parameters from the query string, or null if none were found

request_id

UUID string

Uniquely identifies the request, having the same value found in the original webhook request response in the x-request-id header

webhook_id

UUID string

Identifies the Mechanic webhook which handled the request

{% assign raw_request_body = event.data.body_base64 | decode_base64 %}

Mechanic's webhook request header representation has an important limitation: the array of values for each header is currently limited to a size of one (1). If multiple request headers are given using the same header name, their values will be concatenated with commas and represented in a single string, as the sole array element.

This means that a request which defines both X-Foo: Bar and X-Foo: Baz headers will be represented thusly:

"headers": {
  "x-foo": [
    "Bar,Baz"
  ]
}

Let us first acknowledge that this is ridiculous. đŸ’¯ ✅

When this issue is resolved, the header example above will be represented as follows:

"headers": {
  "x-foo": [
    "Bar",
    "Baz"
  ]
}

Task code that reads webhook request headers should take these two possible representations into account.

Sample "Full request" event data
{
  "body_base64": "LS0tLS0[...]S0NCg==",
  "body": {
    "file_upload": {
      "content_base64": "iVBORw0[...]K5CYII=",
      "mime_type": "image/png",
      "name": "tiny.png",
      "size": 1265
    },
    "key": "value",
    "hash": {
      "key": "hash_value"
    },
    "array": [
      "array_value"
    ]
  },
  "client_ip": "8.8.8.8",
  "headers": {
    "content-length": [
      "1759"
    ],
    "content-type": [
      "multipart/form-data; boundary=----WebKitFormBoundaryqcjvhXaEdqng2TkC"
    ],
    "x-custom": [
      "Value"
    ],
    "x-foo": [
      "Bar,Baz"
    ]
  },
  "mime_type": "multipart/form-data",
  "query_string": "key=value&hash[key]=hash_value&array[]=array_value",
  "query": {
    "key": "value",
    "hash": {
      "key": "hash_value"
    },
    "array": [
      "array_value"
    ]
  },
  "request_id": "a8723f25-20ff-4b89-a46c-73fc387a16d3",
  "webhook_id": "d166806f-1f79-4283-b4b4-80a38ee04431"
}

Requests

The Mechanic webhook API only accepts POST requests. (All other methods will receive a 405 Method Not Allowed response.)

Mechanic's webhook API includes CORS support for all origins, making these requests available for use in online user experiences.

File uploads

File uploads are supported via multipart/form-data webhook requests. Each uploaded file will be represented in event data (regardless of event data mode) as a structured hash having the following keys:

  • content_base64 — A base64 string representation of the file content

  • mime_type — The MIME type of the file, as declared in the headers for that file

  • name — The original name of the file, as declared in the headers for that file

  • size — An integer reflecting the size of the file in bytes

{% assign file = event.data.body.my_upload %}
{% assign raw_file_content = file.content_base64 | decode_base64 %}
File upload sample representation
{
  "my_upload": {
    "content_base64": "PD94bWw[...]mc+Cg==",
    "mime_type": "image/svg+xml",
    "name": "logo.svg",
    "size": 12345
  }
}

Client-specific endpoints

A webhook invocation signals its client selection via a path suffix. Given a webhook URL of webhooks.mechanic.dev/0000..0000, a client-specific endpoint for Ship24 (for example) would be available at webhooks.mechanic.dev/0000..0000/ship24.

Client

Webhook suffix

Behavior notes

Asana

asana

Supports the X-Hook-Secret header for the handshake phase

Ship24

ship24

Supports HEAD requests for webhook verification

Examples

With cURL:

curl -X POST -F foo=bar https://webhooks.mechanic.dev/abcdef12-3456-abcd-ef12-3456abcdef12
curl -X POST -H "content-type: application/json" -d @data.json https://webhooks.mechanic.dev/abcdef12-3456-abcd-ef12-3456abcdef12

With fetch:

const data = {
  some_data: 'yep here it is',
};

fetch(
  'https://webhooks.mechanic.dev/0000-0000',
  {
    method: 'post',
    body: JSON.stringify(data),
    headers: {
      'content-type': 'application/json'
    },
  }
).then(console.log);

With jQuery:

$.post('https://webhooks.mechanic.dev/0000-0000', { foo: 'bar' });
$.ajax({
  url: 'https://webhooks.mechanic.dev/0000-0000',
  method: 'POST',
  data: { foo: 'bar' }
});
let data = { foo: 'bar' };

$.ajax({
  url: 'https://webhooks.mechanic.dev/0000-0000',
  method: 'POST',
  headers: {
    'content-type': 'application/json'
  },
  data: JSON.stringify(data)
});

Responses

A properly-formatted webhook request will always receive a 204 No Content response, even in the case of an incorrect webhook ID in the URL.

If an active webhook ID was used, then an event will be created with the submitted data. The event will be run asynchronously, along with any generated task and action runs that follow.

Webhook request ID

Retrieving run results

The webhook ingress API is solely for ingesting data to form a new event. Because of this, the webhook response necessarily does not contain any data resulting from the runs that might follow. (To further explain the point: there could be zero task runs that follow, or many, and there are no hard guarantees for when those runs would finish.)

This means that the caller must use another avenue for retrieving the results of any generated runs. In general, there are three options for this:

Event topic — The used for events created via this webhook

Decode the base64-encoded request body with Liquid, using Mechanic's filter.

As of this writing (2023-03-08), an upstream provider of Mechanic's does not have proper support for requests containing repeated header names. Mechanic's behavior here is a compromise chosen (1) to allow us to resolve this in the future without requiring a change to the format of this representation, and (2) for consistency with .

Decode base64-encoded file content with Liquid, using Mechanic's filter.

When configuring an integration with external apps and services, some require specific behavior from webhook hosts – usually for the purposes of validating a webhook before it's enabled. Mechanic includes specific support for some known webhook clients; request new ones at .

All POST requests to webhooks.mechanic.dev will receive an x-request-id response header, containing a UUID. This ID can be used as a search term when looking up a Mechanic event, and can be referenced in Liquid as a part of the via event.webhook_request_id.

For a consistently re-occurring call with a single caller, the task responding to the webhook event may write its results to the , allowing the caller to retrieve results using a .

For calls with variable or multiple callers, use the webhook request ID by reading the x-request-id response header in your client code, and by referencing event.webhook_request_id in your task's Liquid code in. Tasks responding to the webhook event should store their results keyed by that UUID, using an external storage mechanism (possibly via the or actions).

For calls triggered by customer activity on an online Shopify storefront, consider (a) requiring the customer to be logged in, (b) sending the customer ID in the webhook request data, (c) storing task results in a customer metafield (using the action), and (d) using storefront Liquid to render the content of that metafield, polling until a value is present.

topic
mechanic.canny.io
Event object
Mechanic cache
cache endpoint
HTTP
FTP
Shopify
Docs
Docs
event
Creating a Mechanic webhook
Postman
docs
HTTP action's response format
decode_base64
decode_base64