development-integrations

Mastering Shopify Local Delivery: Automate 'Mark as Delivered' & Customer Emails with the Admin API

Hey there, fellow store owners and tech-savvy entrepreneurs! At Shopping Cart Mover, we're constantly exploring ways to optimize and streamline e-commerce operations. One area that often presents unique challenges and opportunities for improvement is local delivery. Ensuring timely updates for customers and efficient workflows for drivers can significantly impact your brand's reputation and operational costs.

We recently came across a fantastic discussion in the Shopify Community forums that perfectly illustrates a common pain point: how to automate the crucial 'Mark as delivered' action for local orders, ensuring customers receive their confirmation emails automatically, just as they would with a manual click in the Shopify Admin.

The original query came from Robert77, a developer looking to replicate the native Shopify Admin functionality via the API. This wasn't about standard carrier tracking; it was specifically about Shopify's Local Delivery orders, which often have their own distinct operational nuances.

Flowchart of Shopify local delivery app with API integration and QR code
Flowchart of Shopify local delivery app with API integration and QR code

The Core Challenge: Mimicking Shopify's Native "Mark as Delivered"

Robert77's initial questions were precise, cutting straight to the heart of automating a critical customer touchpoint:

  • Is API automation possible for local delivery confirmations?
  • Which specific Admin API endpoint or GraphQL mutation should be used?
  • What unique identifier is required (Order ID, Fulfillment Order ID, Fulfillment ID, or delivery method ID)?
  • What are the necessary access scopes for the custom app?
  • Will the customer delivery confirmation email be sent automatically, mirroring the manual process?

These are excellent questions that many developers and store owners grapple with when trying to build custom solutions around Shopify's robust platform.

Initial Guidance: The fulfillmentEventCreate Mutation

The community quickly provided solid initial advice, confirming that yes, this automation is absolutely possible through the Shopify Admin API. The key, as pointed out by youssefhe5, is leveraging the fulfillmentEventCreate GraphQL mutation. Here’s a breakdown of the initial guidance:

  • The Mutation: The fulfillmentEventCreate GraphQL mutation is your go-to.
  • The Required ID: You need the Fulfillment ID (e.g., gid://shopify/Fulfillment/123456789). An Order ID alone won't suffice; you'd need to query the order first to retrieve its associated Fulfillment ID.
  • Access Scopes: Your custom app must have the write_fulfillments scope enabled to perform this action.
  • The Email Trigger: Crucially, when you use this mutation to change the status to DELIVERED, Shopify's system automatically dispatches the exact same delivery confirmation email to the customer that the manual button triggers. This ensures a consistent customer experience.

The basic GraphQL mutation and variables look like this:

mutation CreateLocalDeliveryEvent($fulfillmentId: ID!, $fulfillmentEvent: FulfillmentEventInput!) {
  fulfillmentEventCreate(fulfillmentId: $fulfillmentId, fulfillmentEvent: $fulfillmentEvent) {
    fulfillmentEvent {
      id
      status
    }
    userErrors {
      field
      message
    }
  }
}

And the corresponding variables:

{
  "fulfillmentId": "gid://shopify/Fulfillment/YOUR_FULFILLMENT_ID",
  "fulfillmentEvent": {
    "status": "DELIVERED"
  }
}

The Deeper Dive: Robert77's Robust Real-World Solution

While the initial guidance was spot on, Robert77's subsequent update provided invaluable real-world insights, particularly for local delivery scenarios. He shared his successful implementation of a QR-based local delivery confirmation app, highlighting a critical discovery:

The Fulfillment ID Challenge for Local Delivery

For many local delivery orders, a standard Fulfillment ID might not exist at the time an order is initially processed or printed. Even if Shopify has a local delivery/fulfillment order connected, the actual Fulfillment object might not be created until later in the process. This meant a simple QR code containing only a Fulfillment ID wouldn't always work.

The Comprehensive Solution: Dynamic Fulfillment Handling

Robert77's robust solution involved a dynamic approach to finding or creating the necessary Fulfillment object before marking it as delivered. Here's his refined workflow:

  1. Secure Order Identification: The QR code securely identifies the order, not necessarily a fulfillment. This could be an Order ID or a custom secure token.
  2. Backend Lookup: Upon scanning the QR, a custom Node/Express backend looks up the Shopify order.
  3. Check for Existing Fulfillment: The backend first checks if a usable Fulfillment already exists for that order.
  4. Utilize Existing Fulfillment: If a Fulfillment exists, its ID is used.
  5. Query Fulfillment Orders: If no Fulfillment exists, the backend queries the order’s Fulfillment Orders.
  6. Identify Open Local Fulfillment Order: It then finds the relevant open local Fulfillment Order.
  7. Create Fulfillment: A new Fulfillment is created from that Fulfillment Order.
  8. Mark as Delivered: Finally, the newly created (or existing) Fulfillment is marked as delivered using fulfillmentEventCreate with the status DELIVERED.

This sophisticated approach ensures that the app can handle various states of a local delivery order, making it incredibly resilient. The final delivery mutation remains the same, but the preceding logic is crucial:

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": "2026-06-10T00:00:00.000Z" 
  }
}

Note the addition of happenedAt for precise timestamping, which is a good practice.

Expanded API Scopes

To support this comprehensive flow, Robert77's app required a broader set of API scopes:

  • read_orders
  • read_fulfillments
  • write_fulfillments
  • read_merchant_managed_fulfillment_orders
  • write_merchant_managed_fulfillment_orders

The merchant_managed_fulfillment_orders scopes are particularly important for interacting with the Fulfillment Order objects, which are distinct from Fulfillment objects and represent the merchant's intent to fulfill items.

Building Your Own Local Delivery App: Key Takeaways

Inspired by this solution, here are some actionable insights if you're considering building a similar custom app for your Shopify store:

  1. Backend is Essential: A small, externally hosted backend (like Node/Express) is necessary to handle API calls, secure token generation, and business logic.
  2. Secure QR Codes: Implement signed tokens for your QR codes. This ensures that printed codes remain valid even after server restarts or redeployments, enhancing reliability.
  3. Mobile-Friendly Driver Interface: A simple, intuitive mobile web page for drivers to confirm delivery is crucial for usability.
  4. Understand Fulfillment vs. Fulfillment Orders: This distinction is vital for local delivery. Be prepared to create a Fulfillment from a Fulfillment Order if one doesn't already exist.
  5. Implement a "Safe Mode": A testing mode that simulates the entire flow without actually updating live Shopify orders is invaluable for development and quality assurance.

Why This Matters for Your Store

Automating your local delivery confirmation process offers significant benefits:

  • Enhanced Customer Experience: Instant, accurate delivery notifications build trust and reduce customer inquiries.
  • Increased Efficiency: Drivers can quickly mark orders as delivered, reducing administrative overhead and allowing them to focus on deliveries.
  • Improved Data Accuracy: Automated updates minimize human error in order status management.
  • Scalability: As your local delivery operations grow, a robust automated system can scale with your needs without proportional increases in manual effort.

Conclusion

The journey from a simple question in a forum to a fully functional, robust local delivery confirmation app demonstrates the power and flexibility of the Shopify Admin API. By understanding the nuances of Fulfillment and Fulfillment Order objects and leveraging the fulfillmentEventCreate mutation, developers can build powerful custom solutions that significantly enhance operational efficiency and customer satisfaction for local delivery services.

At Shopping Cart Mover, we specialize in helping businesses optimize their e-commerce platforms, whether it's through complex migrations or integrating custom solutions like the one discussed. If you're looking to enhance your Shopify store's capabilities or considering a platform migration, our team of experts is here to help you navigate the complexities and achieve your business goals.

Share:

Use cases

Explore use cases

Agencies, store owners, enterprise — find the migration path that fits.

Explore use cases