Probably one of the more technical Shopify builds I’ve done so far.
The goal was simple from the user side:
Print a QR code on the internal delivery sheet.
Driver scans it after delivery.
A normal mobile webpage opens.
Driver taps “Mark as delivered”.
Shopify updates the local delivery order as delivered.
No driver app. No login. No complicated workflow.
The harder part was Shopify’s fulfillment model.
At first it looked like this could be solved by calling fulfillmentEventCreate with status DELIVERED.
But local delivery orders are not always that straightforward.
When the order sheet is printed, the Shopify order may still be UNFULFILLED. In that state, there may be no normal Fulfillment object available yet, only a local FulfillmentOrder.
So the QR code could not safely rely on a Fulfillment ID being present at print time.
The final flow ended up like this:
The printed QR identifies the order using a signed token
Backend verifies the token
Backend looks up the live Shopify order through the Admin API
It checks whether a usable Fulfillment already exists
If no Fulfillment exists, it queries the order’s Fulfillment Orders
It finds the open LOCAL Fulfillment Order with remaining quantity
It creates a Fulfillment from that Fulfillment Order
It then marks that Fulfillment as delivered using fulfillmentEventCreate
The core mutation is:
mutation MarkDelivered($fulfillmentEvent: FulfillmentEventInput!) {
fulfillmentEventCreate(fulfillmentEvent:
$fulfillmentEvent) {
fulfillmentEvent {
id
status
happenedAt
}
userErrors {
field
message
}
}
}
With variables like:
{
"fulfillmentEvent": {
"fulfillmentId": "gid://shopify/Fulfillment/...",
"status": "DELIVERED",
"happenedAt": "CURRENT_ISO_TIMESTAMP"
}
}
The main workaround was that the app sometimes has to create the Fulfillment first, using fulfillmentCreate, before it can attach the delivered event.
The app is built as a Node/Express backend, deployed on Railway, connected to GitHub, and uses Shopify’s GraphQL Admin API.
It also has a safe mode, so the QR flow, driver page and button can be tested end-to-end without modifying real Shopify orders.
The QR image loads directly in the Shopify print template, but the token itself is signed, so the printed link can identify the order without exposing admin credentials or relying on a stored database record.
Still one final live-store detail to confirm: whether Shopify sends the exact same customer delivery confirmation email when the delivered event is created through the API as when using Shopify’s native “mark as delivered” button.
But the main technical problem is solved.
Scan QR. Verify token. Find order. Resolve fulfillment state. Create fulfillment if needed. Mark delivered.
This one was fun to get working.
#Shopify #ShopifyDev #ShopifyPlus #GraphQL #AdminAPI #NodeJS #ExpressJS #Railway #Ecommerce #WebDevelopment #Automation #LocalDelivery #SmallBusiness