Shopify Payments in Mexico now lists OXXO as a payment method. The customer checks out, gets a barcode and pays cash at an OXXO store. For anyone who writes code against a Shopify store, the important part is what happens in between: the order exists and is unpaid for days.
The short version: if an app, a Flow workflow or a webhook handler starts real work when an order is created, it will now start that work on orders that may never be paid. Ship, invoice and thank people when the order is paid. Keep "created" for things that are fine to do for an unpaid order.
For turning OXXO on and running the orders by hand, Jamak has the merchant guide. This post is the code side.
How long an OXXO order stays unpaid
From Shopify's Help Center, as of October 2026:
- The order is created at checkout with the payment status Payment pending.
- The barcode is valid for 5 days.
- After it expires, the order stays pending for up to 3 more business days, counted on the Mexican calendar, so a payment made near the deadline can still land.
- After the customer pays, confirmation can take up to 3 business days.
Put together, an order can sit unpaid for more than a week. I haven't found a published OXXO launch date from Shopify, and I haven't run OXXO on a production store yet, so what follows is the checklist I'm applying to my own automations, not a report of results.
What the API calls this state
In the GraphQL Admin API, the order's displayFinancialStatus is PENDING. Shopify's enum reference defines it as the status an order has "when the payment provider needs time to complete the payment." When the money arrives it moves to PAID.
Two events matter:
orders/createfires when the order is placed. For OXXO, that is when the customer gets the barcode.orders/paidfires, in Shopify's words, "whenever an order is paid" (webhook topics).
In Shopify Flow, the matching trigger is Order paid, which Shopify's Flow reference says starts a workflow when an order's payment status changes to paid.

The audit: everything that listens to "created"
I list every subscription and workflow that starts on order creation, then sort each one into two buckets.
Move to paid:
- Fulfillment: sending the order to a warehouse, a 3PL or a print-on-demand service.
- Accounting or ERP export of the sale.
- Review requests, loyalty points and "thanks for your purchase" sequences.
Fine on created:
- Logging and analytics that record the order with its status.
- Internal notifications, as long as they say the payment is pending.
- Anything that only reads the order and changes nothing outside Shopify.
The test I use: if the customer never pays, does this action cost money or confuse someone? If yes, it belongs on paid.
Card payments make this easy to miss, because they usually reach PAID right after creation and both events seem to mean the same thing. Shopify's own fulfillment docs already advise against starting fulfillments from orders/create, order_transactions/create or orders/paid for marketplace channels, and point to fulfillment orders instead (source). If your app manages fulfillment orders, check that the fulfillment order is ready before you create a fulfillment.
The handler
Shopify can deliver the same webhook more than once, for example after a timeout or a retry, and it gives you one second to connect and five seconds for the whole request (delivery docs). So the paid handler verifies the signature, drops duplicates by X-Shopify-Webhook-Id, queues the work and answers right away:
// orders/paid: the only place fulfillment starts.
// verifyHmac, seen, markSeen and queue are your own helpers.
export async function onOrderPaid(req, res) {
if (!verifyHmac(req)) return res.sendStatus(401);
const deliveryId = req.get("X-Shopify-Webhook-Id");
if (await seen(deliveryId)) return res.sendStatus(200); // duplicate delivery
await queue.add("fulfil-order", { orderId: req.body.admin_graphql_api_id });
await markSeen(deliveryId);
res.sendStatus(200); // answer fast; the job does the work
}
Make the job itself idempotent per order too: before it sends anything to the warehouse, it checks whether that order was already sent. A duplicate delivery and a second subscription to the same topic should both end in one shipment.
The sweep for orders still pending
Events tell you when something changes. They don't tell you about the order that never changes. Once a day I query the orders that are still pending:
query PendingOrders {
orders(first: 50, query: "financial_status:pending created_at:<2026-10-20") {
nodes {
id
name
createdAt
displayFinancialStatus
paymentGatewayNames
}
}
}
financial_status:pending and created_at are documented filters on the orders query. Replace the date with today minus the window you want, and page through the results if there are more than 50.
The sweep produces a report, not cancellations. Cancelling inside the late window means a customer who paid on time has paid for an order you cancelled. Counting that window right means knowing Mexican public holidays, and I'd rather a person makes that call than a cron job that gets one date wrong.
Two cases deserve their own line in the report:
- Partly paid orders. If a customer paid part of the order another way, such as with a gift card, and never paid the OXXO part, Shopify keeps the order open with that payment applied and its stock reserved. Check how these show up in your store before you write a filter for them.
- Refunds. Shopify Payments can't refund an OXXO payment to the original method. If your app automates refunds, it needs a path for store credit, or for a transfer made outside Shopify that someone then records on the order.
The checklist
- List every webhook subscription, Flow workflow and app that starts on order creation.
- Move fulfillment, accounting exports and post-purchase messages to
orders/paidor Flow's Order paid trigger. - Deduplicate deliveries by
X-Shopify-Webhook-Id, and make each job idempotent per order. - Run a daily
financial_status:pendingsweep that reports, and let a person cancel. - Give refunds a path that doesn't assume the original payment method.
Then tell people you accept OXXO before they reach checkout. Ezeo covers how to make Google and AI assistants know it. For the storefront side of a Shopify build, see my notes on storefront performance that converts.
FAQ
Which webhook should start fulfillment for an OXXO order?
orders/paid, or Flow's Order paid trigger, not orders/create. An OXXO order is created with a pending payment when the customer gets the barcode, and it can stay unpaid for more than a week.
What is the financial status of an unpaid OXXO order in the API?
PENDING in the GraphQL Admin API's displayFinancialStatus. Shopify uses it when the payment provider needs time to complete the payment. You can find these orders with the financial_status:pending filter on the orders query.
Should I auto-cancel OXXO orders that stay pending?
I don't. The barcode is valid for 5 days and the order stays pending for up to 3 more Mexican business days, so an automatic cancel can hit a customer who paid on time. A daily report and a person deciding is safer.




