# How to Automate Shopify Order Fulfillment using the API

- Tool: API Automations
- Difficulty: Intermediate
- Fix time: 30-60 minutes
- Compatibility: Shopify Standard plan or higher; custom app with scopes: read_orders, write_fulfillments, read_fulfillments
- Last updated: May 2026

## TL;DR

Automate Shopify order fulfillment by listening for `orders/paid` webhooks and calling the GraphQL `fulfillmentCreate` mutation with tracking numbers. The critical risk: Shopify silently deletes your webhook subscription after 19 consecutive failed deliveries (~48 hours). Return a 2xx response within 5 seconds or the delivery counts as a failure. Use the modern `fulfillmentOrders` query — the legacy REST `POST /fulfillments.json` endpoint is deprecated.

## Best practices

- Always respond to Shopify webhook deliveries within 5 seconds — use background queues (Celery, BullMQ, SQS) for the actual fulfillment processing.
- Implement idempotency: store each order ID as 'fulfilled' in a database before calling fulfillmentCreate to prevent duplicate fulfillments from re-delivered webhooks.
- Monitor webhook subscription health daily — Shopify's silent deletion after 19 failures is the #1 cause of unexplained gaps in order processing.
- Filter fulfillment orders by `status === 'OPEN'` before attempting to create fulfillments — already-fulfilled or cancelled orders return user errors.
- Use the modern `fulfillmentCreate` with `lineItemsByFulfillmentOrder` — the legacy REST `POST /fulfillments.json` is deprecated and may stop working.
- For partial fulfillments (shipping line items from the same order separately), specify `fulfillmentOrderLineItems` in each fulfillment request.
- Log all fulfillment mutations with order ID, fulfillment order ID, tracking number, and timestamp for customer service lookup.
- Set `notifyCustomer: false` if you're sending custom shipping notifications via your own ESP — otherwise customers get duplicate emails.

## Frequently asked questions

### Why did my Shopify webhook stop receiving events?

Shopify silently deletes webhook subscriptions after 19 consecutive failed deliveries, which take approximately 48 hours. A failed delivery is any response that takes longer than 5 seconds or returns a non-2xx status code. Check your subscription list with `{ webhookSubscriptions(first: 20) { edges { node { id topic } } } }`. If the subscription is missing, re-register it immediately and investigate why deliveries were failing (endpoint downtime, timeout, errors).

### What is the difference between a fulfillmentOrder and a fulfillment?

A `fulfillmentOrder` is Shopify's internal representation of what needs to be shipped — it groups line items by location and tracks fulfillment status. A `fulfillment` is the actual shipment record with tracking information. To fulfill an order, you first query its `fulfillmentOrders` to get the fulfillment order IDs, then call `fulfillmentCreate` with those IDs. You cannot create a fulfillment without first obtaining fulfillment order IDs.

### Can I still use the REST POST /fulfillments.json endpoint?

Yes, for custom apps it currently works. However, Shopify has deprecated REST and declared it 'legacy.' New features go to GraphQL only. All new public apps must use GraphQL since April 1, 2025. For future-proof automation, use `fulfillmentCreate` GraphQL mutation from the start — migrating later requires rewriting the integration.

### How do I fulfill only part of an order (partial fulfillment)?

Use `lineItemsByFulfillmentOrder[].fulfillmentOrderLineItems` to specify exactly which line items and quantities to fulfill. Each object takes a `fulfillmentOrderLineItemId` and optional `quantity`. If some items ship from a different location, Shopify creates separate fulfillment orders per location — fulfill each separately with its own `fulfillmentCreate` call.

### What happens if I call fulfillmentCreate twice for the same order?

The second call returns a userError: 'fulfillmentOrder is not in OPEN status' since the order is already fulfilled after the first call. HTTP status is still 200. This is why idempotency matters — store the Shopify order ID in a database after successful fulfillment and skip re-processing if you receive a duplicate webhook delivery.

### Is the Shopify API free?

The Shopify Admin API is free for apps installed on Shopify stores. There are no API call fees. You pay for your Shopify plan (Basic, Standard, Plus) which determines your GraphQL rate limit bucket size. Third-party infrastructure for webhook endpoints and queuing is your own cost.

### Can RapidDev help build a custom Shopify fulfillment integration?

Yes. RapidDev has built 600+ apps including Shopify fulfillment pipelines connecting to 3PLs, dropshipping suppliers, print-on-demand services, and custom carrier systems. We handle webhook infrastructure, queue setup, and rate limit management. Book a free consultation at rapidevelopers.com.

---

Source: https://www.rapidevelopers.com/api-automations/how-to-automate-shopify-order-fulfillment-using-the-api
© RapidDev — https://www.rapidevelopers.com/api-automations/how-to-automate-shopify-order-fulfillment-using-the-api
