We map order states from fulfillment `status` + `shipment_status` — how to handle `shipment_status = null`?

Hi everyone,

I’m a developer working on a custom integration with the Shopify Admin REST API. We’re trying to derive order status for our own system based on the fulfillment status and shipment_status fields from the order JSON.

Our current understanding and mapping logic is:

  • When status = "success" AND shipment_status = "delivered"
    → We consider the order completed (delivered to the customer).

  • When status = "success" AND shipment_status is one of:

    • "ready_for_pickup"
    • "confirmed"
    • "in_transit"
      → We consider the order shipped but not yet completed (in delivery progress).

However, there is one case we are not sure how to handle:

  • When status = "success" AND shipment_status = null

In this case, we don’t know whether the shipment is:

  • just created,
  • in transit,
  • delivered but not updated,
  • or if Shopify will never update shipment_status for this fulfillment (for example, depending on the carrier).

Here is an example fulfillment object from our order JSON (simplified):slight_smile:

{
  "result": "success",
  "order": {
    "id": 6722543747241,
    "adminGraphqlApiId": "gid://shopify/Order/6722543747241",
    "appId": 580111,
    "browserIp": "2a06:5906:456:da00:c5b2:49:5bc9:cc23",
    "buyerAcceptsMarketing": true,
    "cancelReason": null,
    "cancelledAt": null,
    "cartToken": "hWN7NoDiX2KjIkpI8Jc599O7",
    "checkoutId": 30330558021801,
    "checkoutToken": "79d5e2dcc6f1e57c4a7978722211e5a3",
    "clientDetails": {
      "acceptLanguage": "en-GB",
      "browserHeight": null,
      "browserIp": "2a06:5906:456:da00:c5b2:49:5bc9:cc23",
      "browserWidth": null,
      "sessionHash": null,
      "userAgent": "Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Mobile Safari/537.36"
    },
    "closedAt": "2026-01-13T16:40:29+08:00",
    "confirmationNumber": "7CN5LYELQ",
    "confirmed": true,
    "contactEmail": "patriciagurney46@yahoo.com",
    "createdAt": "2026-01-09T04:50:46+08:00",
    "currency": "USD",
    "currentSubtotalPrice": "36.68",
    "currentSubtotalPriceSet": {
      "shopMoney": {
        "amount": "36.68",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "36.68",
        "currencyCode": "USD"
      }
    },
    "currentTotalAdditionalFeesSet": null,
    "currentTotalDiscounts": "0.00",
    "currentTotalDiscountsSet": {
      "shopMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      }
    },
    "currentTotalDutiesSet": null,
    "currentTotalPrice": "46.68",
    "currentTotalPriceSet": {
      "shopMoney": {
        "amount": "46.68",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "46.68",
        "currencyCode": "USD"
      }
    },
    "currentTotalTax": "0.00",
    "currentTotalTaxSet": {
      "shopMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      }
    },
    "customerLocale": "en-GB",
    "deviceId": null,
    "discountCodes": [],
    "dutiesIncluded": false,
    "email": "patriciagurney46@yahoo.com",
    "estimatedTaxes": false,
    "financialStatus": "paid",
    "fulfillmentStatus": "fulfilled",
    "landingSite": "/collections/red-string-bracelets?gad_source=1&gad_campaignid=23426149622&gclid=Cj0KCQiAyP3KBhD9ARIsAAJLnnZjGIzZrEiNpDSkdxrGHJF4T8Y3O7HMaDXd3XqXUn0vODgBhFb77toaAqTEEALw_wcB",
    "landingSiteRef": null,
    "locationId": null,
    "merchantBusinessEntityId": "MTcwNzkyNDc4ODg5",
    "merchantOfRecordAppId": null,
    "name": "#1002",
    "note": null,
    "noteAttributes": [],
    "number": 2,
    "orderNumber": 1002,
    "orderStatusUrl": "https://zenhima.com/70792478889/orders/c7626154ad11ceb605f6f8b7ed0941e6/authenticate?key=552eb81555a7b384ebfc311211039144",
    "originalTotalAdditionalFeesSet": null,
    "originalTotalDutiesSet": null,
    "paymentGatewayNames": [
      "paypal"
    ],
    "phone": null,
    "poNumber": null,
    "presentmentCurrency": "USD",
    "processedAt": "2026-01-09T04:50:45+08:00",
    "reference": null,
    "referringSite": "android-app://com.google.android.googlequicksearchbox/",
    "sourceIdentifier": null,
    "sourceName": "web",
    "sourceUrl": null,
    "subtotalPrice": "36.68",
    "subtotalPriceSet": {
      "shopMoney": {
        "amount": "36.68",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "36.68",
        "currencyCode": "USD"
      }
    },
    "tags": "",
    "taxExempt": false,
    "taxLines": [],
    "taxesIncluded": false,
    "test": false,
    "token": "c7626154ad11ceb605f6f8b7ed0941e6",
    "totalCashRoundingPaymentAdjustmentSet": {
      "shopMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      }
    },
    "totalCashRoundingRefundAdjustmentSet": {
      "shopMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      }
    },
    "totalDiscounts": "0.00",
    "totalDiscountsSet": {
      "shopMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      }
    },
    "totalLineItemsPrice": "36.68",
    "totalLineItemsPriceSet": {
      "shopMoney": {
        "amount": "36.68",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "36.68",
        "currencyCode": "USD"
      }
    },
    "totalOutstanding": "0.00",
    "totalPrice": "46.68",
    "totalPriceSet": {
      "shopMoney": {
        "amount": "46.68",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "46.68",
        "currencyCode": "USD"
      }
    },
    "totalShippingPriceSet": {
      "shopMoney": {
        "amount": "10.00",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "10.00",
        "currencyCode": "USD"
      }
    },
    "totalTax": "0.00",
    "totalTaxSet": {
      "shopMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      },
      "presentmentMoney": {
        "amount": "0.00",
        "currencyCode": "USD"
      }
    },
    "totalTipReceived": "0.00",
    "totalWeight": 5,
    "updatedAt": "2026-01-13T16:40:29+08:00",
    "userId": null,
    "billingAddress": {
      "firstName": "Patricia",
      "address1": "2 melbourne terrace",
      "phone": "07835331726",
      "city": "milton keynes",
      "zip": "MK13 7AA",
      "province": "England",
      "country": "United Kingdom",
      "lastName": "Gurney",
      "address2": "Bradville",
      "company": null,
      "latitude": 52.0631494,
      "longitude": -0.786771,
      "name": "Patricia Gurney",
      "countryCode": "GB",
      "provinceCode": "ENG"
    },
    "customer": {
      "id": 9206912319657,
      "createdAt": "2026-01-09T04:50:41+08:00",
      "updatedAt": "2026-01-09T04:50:47+08:00",
      "firstName": "Patricia",
      "lastName": "Gurney",
      "state": "disabled",
      "note": null,
      "verifiedEmail": true,
      "multipassIdentifier": null,
      "taxExempt": false,
      "emailMarketingConsent": {
        "state": "subscribed",
        "optInLevel": "single_opt_in",
        "consentUpdatedAt": "2026-01-09T04:50:47+08:00"
      },
      "smsMarketingConsent": null,
      "tags": "",
      "email": "patriciagurney46@yahoo.com",
      "phone": null,
      "currency": "USD",
      "taxExemptions": [],
      "adminGraphqlApiId": "gid://shopify/Customer/9206912319657",
      "defaultAddress": {
        "id": 9721194512553,
        "customerId": 9206912319657,
        "firstName": "Patricia",
        "lastName": "Gurney",
        "company": null,
        "address1": "2 melbourne terrace",
        "address2": "Bradville",
        "city": "milton keynes",
        "province": "England",
        "country": "United Kingdom",
        "zip": "MK13 7AA",
        "phone": "07835331726",
        "name": "Patricia Gurney",
        "provinceCode": "ENG",
        "countryCode": "GB",
        "countryName": "United Kingdom",
        "default": true
      }
    },
    "discountApplications": [],
    "fulfillments": [
      {
        "id": 6219255906473,
        "adminGraphqlApiId": "gid://shopify/Fulfillment/6219255906473",
        "createdAt": "2026-01-13T16:40:28+08:00",
        "locationId": 78320894121,
        "name": "#1002.1",
        "orderId": 6722543747241,
        "originAddress": [],
        "receipt": [],
        "service": "manual",
        "shipmentStatus": null,
        "status": "success",
        "trackingCompany": "YunExpress",
        "trackingNumber": "YT2600901001533875",
        "trackingNumbers": [
          "YT2600901001533875"
        ],
        "trackingUrl": "http://www.yuntrack.com/Track/Detail/YT2600901001533875",
        "trackingUrls": [
          "http://www.yuntrack.com/Track/Detail/YT2600901001533875"
        ],
        "updatedAt": "2026-01-13T16:40:28+08:00",
        "lineItems": [
          {
            "id": 15907526246569,
            "adminGraphqlApiId": "gid://shopify/LineItem/15907526246569",
            "attributedStaffs": [],
            "currentQuantity": 1,
            "fulfillableQuantity": 0,
            "fulfillmentService": "manual",
            "fulfillmentStatus": "fulfilled",
            "giftCard": false,
            "grams": 5,
            "name": "Adjustable 999 Sterling Silver Persimmon Blessing Red String Bracelet – Auspicious for Your Zodiac Year - Persimmon Wish Red String / Pure Silver",
            "price": "36.68",
            "priceSet": {
              "shopMoney": {
                "amount": "36.68",
                "currencyCode": "USD"
              },
              "presentmentMoney": {
                "amount": "36.68",
                "currencyCode": "USD"
              }
            },
            "productExists": true,
            "productId": 8819074859177,
            "properties": [],
            "quantity": 1,
            "requiresShipping": true,
            "sku": "930271207521Persimmon Wish Red String Pure Silver",
            "taxable": true,
            "title": "Adjustable 999 Sterling Silver Persimmon Blessing Red String Bracelet – Auspicious for Your Zodiac Year",
            "totalDiscount": "0.00",
            "totalDiscountSet": {
              "shopMoney": {
                "amount": "0.00",
                "currencyCode": "USD"
              },
              "presentmentMoney": {
                "amount": "0.00",
                "currencyCode": "USD"
              }
            },
            "variantId": 46638489206953,
            "variantInventoryManagement": "shopify",
            "variantTitle": "Persimmon Wish Red String / Pure Silver",
            "vendor": "ZenHima",
            "taxLines": [],
            "duties": [],
            "discountAllocations": []
          }
        ]
      }
    ],
    "lineItems": [
      {
        "id": 15907526246569,
        "adminGraphqlApiId": "gid://shopify/LineItem/15907526246569",
        "attributedStaffs": [],
        "currentQuantity": 1,
        "fulfillableQuantity": 0,
        "fulfillmentService": "manual",
        "fulfillmentStatus": "fulfilled",
        "giftCard": false,
        "grams": 5,
        "name": "Adjustable 999 Sterling Silver Persimmon Blessing Red String Bracelet – Auspicious for Your Zodiac Year - Persimmon Wish Red String / Pure Silver",
        "price": "36.68",
        "priceSet": {
          "shopMoney": {
            "amount": "36.68",
            "currencyCode": "USD"
          },
          "presentmentMoney": {
            "amount": "36.68",
            "currencyCode": "USD"
          }
        },
        "productExists": true,
        "productId": 8819074859177,
        "properties": [],
        "quantity": 1,
        "requiresShipping": true,
        "sku": "930271207521Persimmon Wish Red String Pure Silver",
        "taxable": true,
        "title": "Adjustable 999 Sterling Silver Persimmon Blessing Red String Bracelet – Auspicious for Your Zodiac Year",
        "totalDiscount": "0.00",
        "totalDiscountSet": {
          "shopMoney": {
            "amount": "0.00",
            "currencyCode": "USD"
          },
          "presentmentMoney": {
            "amount": "0.00",
            "currencyCode": "USD"
          }
        },
        "variantId": 46638489206953,
        "variantInventoryManagement": "shopify",
        "variantTitle": "Persimmon Wish Red String / Pure Silver",
        "vendor": "ZenHima",
        "taxLines": [],
        "duties": [],
        "discountAllocations": []
      }
    ],
    "paymentTerms": null,
    "refunds": [],
    "shippingAddress": {
      "firstName": "Patricia",
      "address1": "2 melbourne terrace",
      "phone": "07835331726",
      "city": "milton keynes",
      "zip": "MK13 7AA",
      "province": "England",
      "country": "United Kingdom",
      "lastName": "Gurney",
      "address2": "Bradville",
      "company": null,
      "latitude": 52.0631494,
      "longitude": -0.786771,
      "name": "Patricia Gurney",
      "countryCode": "GB",
      "provinceCode": "ENG"
    },
    "shippingLines": [
      {
        "id": 5598850744489,
        "carrierIdentifier": null,
        "code": "固定运费",
        "discountedPrice": "10.00",
        "discountedPriceSet": {
          "shopMoney": {
            "amount": "10.00",
            "currencyCode": "USD"
          },
          "presentmentMoney": {
            "amount": "10.00",
            "currencyCode": "USD"
          }
        },
        "isRemoved": false,
        "phone": null,
        "price": "10.00",
        "priceSet": {
          "shopMoney": {
            "amount": "10.00",
            "currencyCode": "USD"
          },
          "presentmentMoney": {
            "amount": "10.00",
            "currencyCode": "USD"
          }
        },
        "requestedFulfillmentServiceId": null,
        "source": "shopify",
        "title": "固定运费",
        "taxLines": [],
        "discountAllocations": []
      }
    ]
  }
}

We have read the official Fulfillment REST API docs here:
https://shopify.dev/docs/api/admin-rest/latest/resources/fulfillment

The docs mention that for tracking companies listed on the Shipping Carriers help page, Shopify will automatically update the fulfillment's `shipment_status` field during the fulfillment process. However, in practice, we often see:

- `status = "success"`
- `shipment_status = null`

even when `tracking_company` and `tracking_number` are provided.

Our questions:

1. **Is it expected behavior that `shipment_status` can remain `null` even when `status = "success"` and a supported carrier (for example YunExpress) + tracking number are set?**  
2. **From Shopify's perspective, what is the recommended / best practice way to derive a high-level “order status” from `status` and `shipment_status`?**  
   - For example, is it safe to treat `status = "success"` as “order shipped”, regardless of `shipment_status`?  
   - And then treat `shipment_status` only as an optional enhancement (if present) for more detailed states like `in_transit`, `delivered`, etc.?
3. **If we rely on `shipment_status` to determine whether an order is delivered, is that reliable across carriers, or should we instead call the carrier's API (e.g. YunExpress) directly to confirm delivery?**

We want to design our logic so that:
- It matches Shopify's intended meaning of `status` and `shipment_status`,
- It is robust even when `shipment_status` is `null` for a long time or indefinitely.

Any clarification, best practices, or examples of how other apps/merchants map these fields to their own order states would be greatly appreciated.

Thank you!
1 Like

Hey @huangYunLiang :waving_hand: thanks for reaching out.

Right now, the REST Admin API is considered a legacy API, and we recommend that any new integrations use the GraphQL Admin API instead, so this is likely a limitation of REST.

That said, for your specific use case around deriving order status from fulfillment data, GraphQL actually has significant advantages. The most important of these is an events connection that gives you the full chronological history of tracking events with statuses like IN_TRANSIT, OUT_FOR_DELIVERY, and DELIVERED, if the fulfullment service uses those event types.

You can query the Fulfillment object along with its FulfillmentEvent connection to get much richer tracking data than what’s available via REST on the order object. If you need to programmatically update tracking status based on data from the carrier’s API, you can also use the fulfillmentEventCreate mutation to add events to the fulfillment’s timeline.

Hope this helps.