Skip to main content

Shopify Module

Run a workflow for every Shopify order, customer or product change, and work the store from your flows: read, find, create and update products, stock, orders and customers; cancel, close and fulfil orders; run any Admin GraphQL query.

The Shopify Module adds one Start event on its own Channel, the Shopify Start (Shopify), and four Tasks that work on any Channel. Typical uses: send a WhatsApp confirmation and create a CRM record for every paid order; tag VIP customers after their fifth order; alert the team when a product's stock drops; fulfil an order and set its tracking number when the warehouse confirms a shipment; keep a product catalogue in sync from a supplier file.

Requirements​

  • A Shopify store and a custom app on it: Settings → Apps and sales channels → Develop apps → Create an app. Give it the Admin API access scopes of what the flow does (read_orders/write_orders, read_products/write_products, read_inventory/write_inventory, read_customers/write_customers, read_fulfillments/write_fulfillments, read_locations), install it, and copy its Admin API access token (shpat_…) and API secret key.
  • Admin API version 2025-01 or later (the default is 2026-01).
  • The Shopify Start needs the engine to be reachable from Shopify over https (Engine:PublicBaseUrl).

Configuration​

The Shopify Module is configured per Environment, so Development and Production can use different stores.

FieldTypeRequiredDescription
Store domainstringYesThe store's myshopify.com domain, e.g. my-store.myshopify.com (a custom domain does not work for the API).
Admin API access tokenpasswordYesThe custom app's access token (shpat_…). Stored encrypted.
Webhook signing secretpasswordFor the StartWhat Shopify signs deliveries with. Webhooks the deploy registers (and any webhook created through the API) are signed with the custom app's API secret key; webhooks created in Settings → Notifications → Webhooks are signed with the secret shown on that page.
API versionstringNoYYYY-MM. Empty: 2026-01.
Default inventory locationstringNoName or id of the location Set / Adjust inventory use when the Task leaves its Location empty. Empty: the store's first active location.

Shopify Start​

Starts the Process when the store sends a webhook for one of the listed topics. The event is available as {shopify}.

FieldTypeDefaultDescription
Topicsstringorders/createComma-separated webhook topics as Shopify names them: orders/create, orders/paid, orders/fulfilled, orders/cancelled, orders/updated, customers/create, customers/update, products/create, products/update, inventory_levels/update, fulfillments/create, refunds/create, draft_orders/create, checkouts/create… At least one.
Register the webhooks in Shopify on deploybooleanonEvery deploy creates the webhook subscriptions for the topics in the store (through the custom app's token) and removes the ones no longer listed; deploying a version without the Start removes them. Off: create the webhooks yourself in Shopify (Settings → Notifications → Webhooks, format JSON) with the address the deploy log shows: {engine}/api/ShopifyModule/webhook/{environment token}.
Event variablevariable{shopify}Receives the event.

A deploy is refused when the Topics list is empty or malformed, when the Environment has no store settings or no webhook signing secret, or when the engine's public address is not set and the webhooks are to be registered automatically. Only the subscriptions at this Environment's address are touched: other apps' and other Environments' webhooks stay.

Every delivery is checked against the signing secret (X-Shopify-Hmac-Sha256) and refused when it comes from another store; Shopify's retries of the same event (X-Shopify-Event-Id) start the flow once. A topic the Start does not list fails the run with a message naming it (remove the webhook in Shopify, or add the topic).

{shopify}​

FieldDescription
topic, kind, actionorders/create → orders, create. Branch on {shopify.topic} when several topics are listed.
shopThe store (my-store.myshopify.com).
id, gidThe resource's id (as text) and global id (gid://shopify/Order/…).
resourceThe payload as Shopify sends it, snake_case: {shopify.resource.name}, {shopify.resource.email}, {shopify.resource.total_price}, {shopify.resource.line_items.0.title}, {shopify.resource.shipping_address.city}.
eventId, webhookId, triggeredAt, apiVersionDelivery details.
from, to, channel, isTestShared by every Start: the customer's email (or the store) and the store; Shopify, or Chat in a test.

Test chat. Testing the flow from the chat runs the Start with a sample order (or customer / product, by the first topic) with {shopify.isTest} = true. Test data can set topic, shop, email, name, total, orderName, title, or a whole resource as JSON.

Shopify products​

One Task, seven operations. The result is written to the Output variable.

OperationFieldsOutput
Get productProduct: id, global id or handleThe product: id, legacyId, title, handle, status, vendor, productType, tags, descriptionHtml, totalInventory, onlineStoreUrl, featuredImage.url, priceRangeV2.minVariantPrice.amount, options, variants (each id, sku, price, compareAtPrice, inventoryQuantity, selectedOptions, inventoryItem.id).
Find productsSearch query (Shopify syntax: title:*shirt* status:active tag:sale vendor:Acme), Maximum results (1–250, default 25)A list of products, most recently updated first.
Create productTitle (required), Description (HTML), Vendor, Product type, Status (empty: draft), Price (of the default variant), TagsThe new product.
Update productProduct, then any of Title, Description, Vendor, Product type, Status, Add tags, Remove tagsThe updated product.
Get inventoryVariant: SKU, id or global id; Location (empty: every location)variantId, sku, title, productId, productTitle, inventoryItemId, tracked, available (the sum) and levels (per location: location, locationId, available, on_hand, committed, incoming, reserved).
Set inventoryVariant, Location (empty: the Environment's default), Quantity (the new available quantity), ReasonThe same shape, for that location.
Adjust inventoryVariant, Location, Quantity (the change, e.g. -1), ReasonThe same shape, for that location.

Reasons are Shopify's: correction (default), received, damaged, shrinkage, restock, cycle_count_available, movement_created… Stock can only be changed on variants whose quantity Shopify tracks.

Shopify orders​

OperationFieldsOutput
Get orderOrder: number (#1001), id or global idThe order: id, legacyId, name, email, phone, createdAt, displayFinancialStatus, displayFulfillmentStatus, currencyCode, subtotalPrice, totalShippingPrice, totalTax, totalDiscounts, totalPrice, totalRefunded (each {amount, currencyCode}), customer, shippingAddress, billingAddress, shippingLine, lineItems (each title, quantity, sku, variantTitle, originalUnitPrice, discountedTotal), fulfillments (each status, trackingInfo), customAttributes, note, tags.
Find ordersSearch query (financial_status:paid fulfillment_status:unfulfilled email:ada@example.com created_at:>2026-01-01 tag:vip), Maximum resultsA list of orders, newest first.
Update orderOrder, then any of Note, Customer email, Add tags, Remove tagsThe updated order.
Cancel orderOrder, Reason (customer, declined, fraud, inventory, staff, other), Refund the customer, Restock the items, Notify the customer, Staff noteThe order, read back (Shopify cancels in the background: cancelledAt may still be empty).
Close orderOrderThe closed (archived) order.
Fulfill orderOrder, Tracking number, Carrier, Tracking URL, Notify the customerorderName, fulfillmentOrderIds and fulfillment (id, status, trackingInfo). Every open item of the order is fulfilled in one fulfillment; an order with nothing left to fulfil fails.

Shopify customers​

OperationFieldsOutput
Get customerCustomer: email, id or global idThe customer: id, legacyId, firstName, lastName, displayName, email, phone, note, tags, state, numberOfOrders, amountSpent, defaultAddress, addresses, emailMarketingConsent.marketingState.
Find customersSearch query (tag:vip country:IT orders_count:>5), Maximum resultsA list of customers, newest first.
Create customerEmail or Phone (one required), First name, Last name, Note, Tags, Subscribed to email marketingThe new customer.
Update customerCustomer, then any of Email, Phone, First name, Last name, Note, Add tags, Remove tagsThe updated customer.

Shopify GraphQL​

For anything the other Tasks don't cover (discounts, metafields, collections, draft orders, shop details…).

FieldDescription
GraphQL queryA query or mutation document. Declare its variables ($id: ID!).
Variables (JSON)A JSON object with the variables. {placeholders} inside its string values are replaced with flow variables, e.g. {"id": "gid://shopify/Order/{shopify.resource.id}"}.
Output variableThe response's data, tidied.

Example: query($id: ID!) { order(id: $id) { name metafield(namespace: "custom", key: "gift") { value } } } with {"id": "gid://shopify/Order/{shopify.resource.id}"} → {result.order.metafield.value}.

A mutation whose payload reports userErrors fails the Task with their messages.

Results and errors​

Every result is a plain object: GraphQL connections come back as lists, money bags (totalPriceSet.shopMoney) as totalPrice: {amount, currencyCode}, and every object with a global id also has legacyId (the number). Webhook payloads keep Shopify's own keys.

A missing product, order or customer, an empty required field, settings missing in the Environment and a malformed value are task errors (fix the flow or the settings). Shopify refusing the token (401/403: check the token and the app's scopes), a rate limit that two retries did not clear (429 / THROTTLED), a mutation's userErrors and an unreachable store are module errors. Give the Tasks an error flow.