# Shopify

Manage a Shopify store: orders, products and variants, customers, inventory, locations and fulfillments.

## Connect Shopify

1. In the sidebar, open **Connections** and press **Add connection**.
2. Type `shopify` and choose **Shopify**.
3. Choose **Sign in with Shopify**.
4. Fill in **Store**.
5. Press **Sign in with Shopify** at the bottom of the sheet, then choose your account in Shopify’s window and allow access.

Before you sign in, the sheet asks:

- **Store · Required**: The store’s myshopify.com name: acme for acme.myshopify.com (the address in Shopify admin’s URL bar).

Or choose **Paste your admin API access token**, fill in **Store** and **Admin API access token**, and press **Test and save**. It stays until someone deletes it.

Sign in to your Shopify store, or paste the Admin API access token of a custom app the store already has (Shopify admin → Settings → Apps and sales channels → Develop apps; it needs the scopes the steps use) with the store’s name. Shopify signs the webhooks it sends with the app’s secret; steps do not need it.

**What if it says “Sign-in isn’t set up here yet”?**

Signing in with Shopify needs a Shopify app on this installation, and it has none yet. Until it is set up, **Paste your admin API access token** works without it.

**On Cloud:** The sheet says “It’s set up once for everyone who uses this service, not by an organization.”

**Self-hosted:** An admin of the installation sees **Set up Shopify sign-in** instead, and sets it up once for everyone. Everyone else sees who to ask.

1. Create an app in Shopify’s developer settings ([Shopify’s guide](https://help.shopify.com/en/manual/apps/app-types/custom-apps)).
2. In GoRunner, copy the **Redirect address to add in Shopify’s developer settings**, and add it to the app.
3. Paste the **Client ID** and **Client secret**, then press **Save and sign in**.

[Set up a sign-in app](https://docs.gorunner.io/self-host/oauth-apps#other-providers)

**Can I use my own Shopify app?**

Yes. In the sheet, open **Use your own Shopify app** and paste its **Client ID** and **Client secret**. Add the redirect address it shows to your app first. The connection then signs in through your app instead of the installation’s.

[Connections](https://docs.gorunner.io/build/connections) says how to sign in again, rename or delete it. In a product that embeds GoRunner, **Add connection** can be missing: then [your provider makes connections](https://docs.gorunner.io/embed/customer-connections) for you.

## Start a workflow

Add a trigger and choose **Shopify**. The trigger uses the same connection as the steps.

### On Shopify Event

Fires when the store sends the chosen event. Publishing the workflow subscribes it at Shopify; unpublishing removes the subscription. Every delivery's X-Shopify-Hmac-Sha256 is checked with the app's secret (the connection's OAuth client secret, or a custom app's API secret key) and an unsigned or wrongly signed one is refused; a retry of the same event starts no second run. The connection needs the read scope of the topic (read_orders for orders…).

- **Event · Required**: What starts the workflow. Options: App: uninstalled to Themes: update (needs read_themes) (82 options). Default: Orders: create.

A later step can use its data, such as `{{trigger.admin_graphql_api_id}}`, `{{trigger.id}}`, `{{trigger.shopify}}`. See [Use data from earlier steps](https://docs.gorunner.io/build/use-data-from-earlier-steps).

## Do things in Shopify

Add a **Shopify** step, choose a **Resource**, then an **Operation**. Choose a row to see its fields.

- [Order](https://docs.gorunner.io/apps/shopify#fields-f-order): Create · Delete · Get · Get Many · Update · Cancel · Close · Mark as Paid
- [Product](https://docs.gorunner.io/apps/shopify#fields-f-product): Create · Delete · Get · Get Many · Update
- [Product Variant](https://docs.gorunner.io/apps/shopify#fields-f-productvariant): Get · Update
- [Customer](https://docs.gorunner.io/apps/shopify#fields-f-customer): Create · Delete · Get · Get Many · Update
- [Inventory](https://docs.gorunner.io/apps/shopify#fields-f-inventory): Adjust · Set · Get Levels
- [Location](https://docs.gorunner.io/apps/shopify#fields-f-location): Get Many
- [Fulfillment](https://docs.gorunner.io/apps/shopify#fields-f-fulfillment): Get Fulfillment Orders · Create · Update Tracking · Cancel

Later steps read a step’s output by its name: see [Use data from earlier steps](https://docs.gorunner.io/build/use-data-from-earlier-steps).

## Limits

- A reply from Shopify can be up to 16 MB (a file download can have its own limit). A larger one fails the step; it is never cut short.
- When Shopify says to slow down (429), the step waits as long as it asks, if the step’s time allows. Otherwise it fails and says when to try again.

Not in your list? See [When an app isn’t here](https://docs.gorunner.io/apps/when-an-app-isnt-here#q-not-in-list).

## For developers

In the API, which calls apps pieces, Shopify is `pieceId: "shopify"` with `actionId: "shopify"`, set by `resource` and an `operation_…` field, such as `operation_customer`. Its trigger is `shopifytrigger` / `shopify_event`. [Get an app](https://docs.gorunner.io/api/apps/get-app) returns every field.

It can change something outside the run (`writes_external`). See [How versions and side effects work](https://docs.gorunner.io/apps#q-versions).

### Shopify › Order

### Create

- **Line Items · Required**: What was bought, such as [{"variantId": "gid://shopify/ProductVariant/123", "quantity": 2}].
- **Email · Optional**: The customer's email.
- **Currency · Optional**: Three-letter code, such as EUR. Empty uses the store's.
- **Financial Status · Optional**: What the order's payment status is set to. Options: PENDING, AUTHORIZED, PAID, PARTIALLY_PAID, PARTIALLY_REFUNDED, REFUNDED, VOIDED, EXPIRED.
- **Customer ID · Optional**: The customer's id: the number in the admin's URL, or its gid://shopify/Customer/… id.
- **Shipping Address · Optional**: {"firstName", "lastName", "address1", "city", "zip", "countryCode": "DE", "phone"}.
- **Billing Address · Optional**: The same shape as the shipping address.
- **Note · Optional**: A note on the order, seen by staff.
- **Tags · Optional**: Separated by commas.
- **Test Order · Optional**: Mark it a test order.
- **Send Receipt · Optional**: Email the customer the order confirmation.
- **Send Fulfillment Receipt · Optional**: Email the customer when it ships.
- **Inventory · Optional**: Whether creating the order takes stock. Options: BYPASS, DECREMENT_IGNORING_POLICY, DECREMENT_OBEYING_POLICY.
- **Additional Fields · Optional**: More of OrderCreateOrderInput's fields for the order, as JSON by their GraphQL names. The fields above win over the same names here.

### Delete, Get, Close and Mark as Paid

- **Order ID · Required**: The order's id: the number in the admin's URL, or its gid://shopify/Order/… id.

### Get Many

- **Status · Optional**: Only orders in this state. Without the read_all_orders scope Shopify lists the last 60 days only. Options: open, closed, cancelled, any.
- **Financial Status · Optional**: Only orders with this payment status. Options: authorized, pending, paid, partially_paid, refunded, voided, partially_refunded, unpaid.
- **Fulfillment Status · Optional**: Only orders with this fulfillment status. Options: shipped, partial, unshipped, unfulfilled.
- **Created After · Optional**: Only orders created at or after this moment. A date or date-time (RFC 3339).
- **Created Before · Optional**: Only orders created before this moment. A date or date-time (RFC 3339).
- **Updated After · Optional**: Only orders changed at or after this moment. A date or date-time (RFC 3339).
- **Search Query · Optional**: More filters in Shopify's search syntax, such as email:ada@example.com or tag:wholesale.
- **Sort By · Optional**: The order of the list. Options: CREATED_AT, UPDATED_AT, PROCESSED_AT, ORDER_NUMBER, TOTAL_PRICE, ID.
- **Newest First · Optional**: Reverse the order (newest or largest first).
- **Return All · Optional**: Read every order, page by page (at most 1000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many orders to return (1–1000). Default: 50. Shows when **Return All** is off.

### Update

- **Email · Optional**: The customer's email.
- **Shipping Address · Optional**: {"firstName", "lastName", "address1", "city", "zip", "countryCode": "DE", "phone"}.
- **Note · Optional**: A note on the order, seen by staff.
- **Tags · Optional**: Separated by commas.
- **Additional Fields · Optional**: More of OrderCreateOrderInput's fields for the order, as JSON by their GraphQL names. The fields above win over the same names here.
- **Order ID · Required**: The order's id: the number in the admin's URL, or its gid://shopify/Order/… id.
- **PO Number · Optional**: The purchase order number.

### Cancel

- **Order ID · Required**: The order's id: the number in the admin's URL, or its gid://shopify/Order/… id.
- **Reason · Required**: Why it is cancelled. Options: CUSTOMER, DECLINED, FRAUD, INVENTORY, OTHER, STAFF.
- **Refund · Optional**: Refund what was paid to the original payment method.
- **Restock · Optional**: Put the items back in stock.
- **Notify Customer · Optional**: Email the customer.
- **Staff Note · Optional**: Kept on the order, seen by staff.

### Shopify › Product

### Create

- **Title · Optional**
- **Description · Optional**: HTML allowed.
- **Handle · Optional**: The product's URL slug. Empty makes one from the title.
- **Product Type · Optional**
- **Vendor · Optional**
- **Tags · Optional**: Separated by commas.
- **Status · Optional**: Active (on sale), draft or archived. Options: ACTIVE, DRAFT, ARCHIVED.
- **Additional Fields · Optional**: More of ProductCreateInput / ProductUpdateInput's fields for the product, as JSON by their GraphQL names. The fields above win over the same names here.

### Delete and Get

- **Product ID · Required**: The product's id: the number in the admin's URL, or its gid://shopify/Product/… id.

### Get Many

- **Search Query · Optional**: More filters in Shopify's search syntax, such as tag:summer or inventory_total:\<5.
- **Status · Optional**: Only products in this status. Options: active, draft, archived.
- **Vendor · Optional**: Only this vendor's products.
- **Product Type · Optional**: Only products of this type.
- **Sort By · Optional**: The order of the list. Options: TITLE, CREATED_AT, UPDATED_AT, INVENTORY_TOTAL, PRODUCT_TYPE, VENDOR, ID.
- **Reverse · Optional**: Reverse the order.
- **Return All · Optional**: Read every product, page by page (at most 1000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many products to return (1–1000). Default: 50. Shows when **Return All** is off.

### Update

- **Title · Optional**
- **Description · Optional**: HTML allowed.
- **Handle · Optional**: The product's URL slug. Empty makes one from the title.
- **Product Type · Optional**
- **Vendor · Optional**
- **Tags · Optional**: Separated by commas.
- **Status · Optional**: Active (on sale), draft or archived. Options: ACTIVE, DRAFT, ARCHIVED.
- **Additional Fields · Optional**: More of ProductCreateInput / ProductUpdateInput's fields for the product, as JSON by their GraphQL names. The fields above win over the same names here.
- **Product ID · Required**: The product's id: the number in the admin's URL, or its gid://shopify/Product/… id.

### Shopify › Product Variant

### Get

- **Variant ID · Required**: The variant's id: the number in the admin's URL, or its gid://shopify/ProductVariant/… id.

### Update

- **Variant ID · Required**: The variant's id: the number in the admin's URL, or its gid://shopify/ProductVariant/… id.
- **Product ID · Required**: The product's id: the number in the admin's URL, or its gid://shopify/Product/… id.
- **Price · Optional**: Decimal text, such as 19.95.
- **Compare-at Price · Optional**: The was-price shown struck through, such as 24.95.
- **SKU · Optional**
- **Barcode · Optional**: ISBN, UPC, GTIN….
- **Additional Fields · Optional**: More of ProductVariantsBulkInput's fields for the variant, as JSON by their GraphQL names. The fields above win over the same names here.

### Shopify › Customer

### Create

- **Email · Optional**
- **First Name · Optional**
- **Last Name · Optional**
- **Phone · Optional**: In E.164 form, such as +4915112345678.
- **Note · Optional**: Seen by staff.
- **Tags · Optional**: Separated by commas.
- **Addresses · Optional**: such as [{"address1": "1 Main St", "city": "Berlin", "zip": "10115", "countryCode": "DE"}].
- **Additional Fields · Optional**: More of CustomerInput's fields for the customer, as JSON by their GraphQL names. The fields above win over the same names here.

### Delete and Get

- **Customer ID · Required**: The customer's id: the number in the admin's URL, or its gid://shopify/Customer/… id.

### Get Many

- **Search Query · Optional**: Filters in Shopify's search syntax, such as email:ada@example.com or tag:vip.
- **Newest First · Optional**: Reverse the order.
- **Return All · Optional**: Read every customer, page by page (at most 1000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many customers to return (1–1000). Default: 50. Shows when **Return All** is off.

### Update

- **Email · Optional**
- **First Name · Optional**
- **Last Name · Optional**
- **Phone · Optional**: In E.164 form, such as +4915112345678.
- **Note · Optional**: Seen by staff.
- **Tags · Optional**: Separated by commas.
- **Additional Fields · Optional**: More of CustomerInput's fields for the customer, as JSON by their GraphQL names. The fields above win over the same names here.
- **Customer ID · Required**: The customer's id: the number in the admin's URL, or its gid://shopify/Customer/… id.

### Shopify › Inventory

### Adjust

- **Inventory Item ID · Required**: The inventory item's id: the number in the admin's URL, or its gid://shopify/InventoryItem/… id.
- **Location ID · Required**: The location's id: the number in the admin's URL, or its gid://shopify/Location/… id.
- **Change · Required**: How much to add (or, below zero, take away) from what is available.
- **Expected Current Quantity · Optional**: Change only if the available quantity is still this; Shopify refuses the change otherwise. Empty skips the check.
- **Reason · Optional**: Why the stock changes (shown in the inventory history). Options: correction to shrinkage (17 options). Default: correction.
- **Reference · Optional**: A URI for what caused the change, such as gid://myapp/StockTake/42 or logistics://warehouse/take/2026-11.

### Set

- **Inventory Item ID · Required**: The inventory item's id: the number in the admin's URL, or its gid://shopify/InventoryItem/… id.
- **Location ID · Required**: The location's id: the number in the admin's URL, or its gid://shopify/Location/… id.
- **Expected Current Quantity · Optional**: Change only if the available quantity is still this; Shopify refuses the change otherwise. Empty skips the check.
- **Reason · Optional**: Why the stock changes (shown in the inventory history). Options: correction to shrinkage (17 options). Default: correction.
- **Reference · Optional**: A URI for what caused the change, such as gid://myapp/StockTake/42 or logistics://warehouse/take/2026-11.
- **Quantity · Required**: The available quantity to set.

### Get Levels

- **Inventory Item ID · Required**: The inventory item's id: the number in the admin's URL, or its gid://shopify/InventoryItem/… id.

### Shopify › Location

### Get Many

- **Return All · Optional**: Read every location, page by page (at most 1000; past that the step fails rather than stop early). Off by default.
- **Limit · Optional**: How many locations to return (1–1000). Default: 50. Shows when **Return All** is off.

### Shopify › Fulfillment

### Get Fulfillment Orders

- **Order ID · Required**: The order's id: the number in the admin's URL, or its gid://shopify/Order/… id.

### Create

- **Fulfillment Order ID · Required**: The fulfillment order's id: the number in the admin's URL, or its gid://shopify/FulfillmentOrder/… id.
- **Line Items · Optional**: Which lines of the fulfillment order to ship, such as [{"id": "gid://shopify/FulfillmentOrderLineItem/1", "quantity": 1}]. Empty ships all of it.
- **Carrier · Optional**: such as DHL Express, UPS.
- **Tracking Number · Optional**
- **Tracking URL · Optional**
- **Notify Customer · Optional**: Email the customer the shipping confirmation.

### Update Tracking

- **Carrier · Optional**: such as DHL Express, UPS.
- **Tracking Number · Optional**
- **Tracking URL · Optional**
- **Notify Customer · Optional**: Email the customer the shipping confirmation.
- **Fulfillment ID · Required**: The fulfillment's id: the number in the admin's URL, or its gid://shopify/Fulfillment/… id.

### Cancel

- **Fulfillment ID · Required**: The fulfillment's id: the number in the admin's URL, or its gid://shopify/Fulfillment/… id.

Source: https://docs.gorunner.io/apps/shopify
