Highlights
  • The change request and the pick happen at the same time, in two systems that cannot see each other.
  • The build is an exception, not a notification: raise it, give it an owner, pause the next handoff, and confirm the change actually landed.
  • The prompt reads a support message and tells you what changed, which order it belongs to, and whether it is still catchable.
  • The script holds the fulfillment first and asks questions second, because a hold is reversible and a shipped package is not.
  • Every store has a version of this window, and closing it is the cheapest way to catch order changes before the label prints.

Welcome to The Loop. Every Wednesday we take one real, repetitive workflow that someone does by hand and unwind it into something you can run. This week: the message that says "sorry, can you send it to my work address instead," arriving at 9:14am while the order it refers to is already on a pick list.

The boring task you repeat is a specification in disguise. Running down the hall to ask whether something has been picked yet is not judgment work, it is a lookup you perform because no system was ever asked to perform it. The moment you can describe what you check, in what order, and what you do with each answer, you can hand the whole thing off. Describing replaces doing.

This loop comes from a merchant thread on the Shopify Community, where somebody answering "what task do you wish you could automate" described the failure exactly: the customer hears we fixed it while the original version is already being prepared. Two true things, one order, nobody holding the line between them. Let us walk it.

The Loop, in Full

See the loop clearly before automating it, because the automatable part is not the fix, it is the race. Marcus runs fulfillment for a nine-person brand that sells engraved gifts, which means every order has a personalization field and a window in which that field still matters. At 9:14am a customer emails: wrong apartment number. At 9:14am the morning batch is already printed and the engraver is three orders away. Marcus does not know that yet, because the inbox and the pick station are different rooms and different software.

  1. Read the message in the shared inbox and work out which order it refers to, usually from a name and a partial date rather than an order number.
  2. Open the order in the admin and check whether it is unfulfilled, partly fulfilled, or already gone.
  3. Ask the warehouse channel whether that one has been picked, printed, or engraved yet, then wait for somebody to look.
  4. Make the change if it is still catchable, or write the apology if it is not.
  5. Reply to the customer, then remember to check later that the change made it onto the pack slip and not just into the order notes.

Every step here is easy, which is exactly why it never gets fixed. There is no hard decision in the list: the hardest thing Marcus does is match a name to an order and read a status field. What makes it expensive is that the five steps have to happen in a specific order, inside a window nobody measures, while two other people are mid-task. That combination, trivial steps plus real time pressure, is the signature of work that belongs to a machine, and it is the same reason the rest of the back office eventually gets handed to a workflow that runs store operations without you.

The Manual Tax

The cost is not the two minutes of looking. It is the shipment you pay for twice and the customer who was told the opposite of what happened.

Put a hard number on the cheapest version of this failure. A package that goes out with an address the customer already corrected does not quietly fix itself: the carrier fixes it and bills you. UPS publishes an Address Correction surcharge of $25.25 per package on both air and ground service, effective December 22, 2025, capped at $175.25 per shipment. That is the floor, and it applies to the lucky outcome where the carrier catches the problem in transit. The unlucky outcome is a package delivered to an apartment where nobody lives, which costs the item, the outbound shipping, the replacement shipping, and the support thread.

  • Errors. The characteristic mistake here is not missing the request, it is answering it. Somebody replies "all set, we updated it" because the order record now says the right thing, while the label printed eleven minutes earlier says the old thing. You have now converted a shipping problem into a trust problem: the customer stops checking, the wrong package arrives anyway, and the second conversation starts from a promise you broke. Personalization makes it worse, because an engraving cannot be corrected in transit at any price.
  • Latency. The window is measured in minutes and the inbox is checked in hours. Most small teams sweep support two or three times a day, which means the average change request is read long after the thing it wanted to change has happened. Nothing is slow here except the hand-off, and the hand-off is the only part that is yours to fix.

A change request is not a message, it is a clock. Treat it like mail and you will answer it correctly and still be wrong.

So the goal is not to read the inbox faster. The goal is to make it structurally impossible for a request to arrive without the clock stopping, which is what it means to put order changes on autopilot rather than racing them.

Unwinding the Loop

Automating starts with description, not code. Write this one down and something useful falls out: almost nothing in the loop is about making the change. It is about buying the time in which the change is still possible.

Part of the loopWhat it is for this workflow
TriggerAn inbound message, not a schedule. Every new email or chat in the support queue, read the moment it lands.
InputThe message text, the sender, and whatever the message mentions: a name, an order number, a date, a product. Plus the current fulfillment state of any order that matches.
DecisionIs this a change request at all, and of what kind: address, quantity, cancellation, personalization, or something that only looks like one ("where is my order" is not a change request).
DecisionIs it still catchable. Unfulfilled and unheld means yes, hold it now. Already fulfilled means no, and the reply has to say so honestly rather than optimistically.
OutputA hold on the fulfillment order with a reason the warehouse can read, an exception record with one named owner and a deadline, and an acknowledgment to the customer that says what is actually true.
Success signalNo order ships with an unresolved change exception attached, and every exception is closed by a person or a rule rather than by the package leaving.

Four of those rows are plumbing and two are judgment, and notice which two. Deciding whether a message is a change request, and deciding whether it is still catchable, are the entire job. Everybody on the team already makes both calls correctly in their head several times a week and has never once written them down. The triage half of this will feel familiar if you read our installment on sorting inbound tickets, and the move is the same: the classification is not the point, the action attached to the classification is the point.

Try It Now

Tell BYOBot how your store handles order changes and it will design the exception: the hold, the owner, the deadline, and the reply that is honest about whether the change landed.

Help me catch order changes before fulfillment…

The Build: One Loop, Three Ways to Run It

The same described loop becomes three builds, and which one you want depends only on how much of the clock you are willing to leave to a person. Start at the top and stop whenever it is good enough.

The Prompt

You can run this today with no setup and no integration. Paste a batch of unread support messages into any AI chat tool along with a short list of your open orders and their fulfillment states, and ask it to do the triage you do by eye.

You are triaging inbound customer messages for an online store.
Your only job is to find requests to CHANGE an order that has
already been placed, and to say how urgent each one is.

I will give you two things:
1. MESSAGES: sender name, email, timestamp, body.
2. OPEN ORDERS: order_number, customer name, email, placed_at,
   fulfillment_status (unfulfilled / partial / fulfilled),
   on_hold (yes/no), shipping_address, line_items.

For each message, output one row with:
- message_id
- is_change_request: yes / no / unclear
- change_type: address | quantity | item_swap | cancel |
  personalization | other | none
- matched_order: the order_number, or NO_MATCH
- match_basis: what you matched on (email, name + date, explicit
  order number). Say NO_MATCH if two orders fit equally well.
- catchable: yes if fulfillment_status is unfulfilled and on_hold
  is no; no if fulfilled; unclear if partial
- requested_value: the exact new address, quantity, or text the
  customer asked for, copied verbatim, or NONE
- action: HOLD_AND_ESCALATE if catchable is yes,
  TOO_LATE_REPLY if catchable is no,
  ASK_CUSTOMER if matched_order is NO_MATCH or the request is
  ambiguous

Rules:
- "Where is my order" and tracking questions are NOT change
  requests. change_type is none.
- Never guess an order number. NO_MATCH is a correct answer.
- Never normalize or tidy the requested_value. Copy it exactly,
  including typos, so a human can compare it to the original.
- If a message contains two requests, output two rows.

Sort the output with HOLD_AND_ESCALATE first, oldest message
first. End with a count of each action type.

Run that against yesterday's inbox and you will find at least one request that was answered politely and never actually applied. It works the same in ChatGPT, Claude, or Gemini, and it is the right first step before you wire anything up, because it tells you how often this happens to you specifically. It also makes the shape of the eventual build obvious, which is the part most people skip when they try to route inbound requests to the right action automatically.

The Script

Here is the honest version: this build needs a model for exactly one step and no model at all for the rest. Reading a free-text email and working out that it is an address change for order 10482 is a language problem, so a model earns its place there. Everything that follows is plain API work, and it should stay that way, because the actions are irreversible and deterministic code is what you want touching them. Both halves are available over an API, so nothing has to navigate a browser. On Shopify, holding a fulfillment is a single call to Shopify's Admin GraphQL API, with a reason and free-text notes the warehouse can read and a matching release mutation to undo it. Read the Shopify Help Center page on order editing before you pick your rules, because it is specific about what an edit can touch and it frames the whole feature as something you do before fulfillment, which is the constraint this entire build exists to respect.

on new_support_message(msg):

    # 1. the one AI step: read, do not act
    read = classify(msg)        # change_type, requested_value,
                                # candidate customer email/name
    if read.change_type == none: return

    # 2. plain lookup, no model
    orders = find_orders(email = msg.sender, placed_within = 30d)
    order  = single_match(orders, read)   # or None

    if order is None:
        open_exception(msg, state = NEEDS_CUSTOMER)
        reply_asking_for_order_number(msg)
        return

    fo = get_fulfillment_order(order)

    # 3. stop the clock FIRST, ask questions after
    if fo.status == OPEN and not fo.on_hold:
        hold_fulfillment(fo,
            reason      = "OTHER",
            reason_notes = "Customer change request: "
                           + read.change_type,
            notify       = true)
        held = true
    else:
        held = false

    # 4. the exception: owner, deadline, state
    open_exception(
        order     = order,
        type      = read.change_type,
        requested = read.requested_value,   # verbatim
        owner     = on_call_ops_person(),
        due_in    = 2h,
        state     = HELD if held else TOO_LATE)

    # 5. tell the truth, not the hope
    if held:
        reply(msg, "We have paused this order while we apply
                    the change. You will get a confirmation
                    once it is done.")
    else:
        reply(msg, "This order has already shipped, so we
                    cannot change it. Here is what we can do
                    instead.")

# closing the loop is a separate, deterministic check
on exception_closed(e):
    assert order_now_matches(e.requested)   # verify, do not trust
    release_hold(e.order)
    reply(e.customer, "Change applied: " + e.requested)

Look at where the model is and is not. It reads, and then it stops. It never edits a quantity, never moves money, never decides that a cancellation is fine. The hold is the only thing that happens automatically, and the hold is chosen precisely because it is cheap to undo: the worst case is an order that sat still for twenty minutes. BYOBot writes the full version of this, including the match logic and the exception store, which is the fastest way to wire your store into a workflow that acts on its own without handing it the keys to your order totals.

The Schedule

This loop is event-driven, so the schedule does something different here: it catches what the events miss. The webhook handles the arrival of a message, but two things still need a timer. First, the sweeper: any exception still open past its deadline gets escalated, and any order on hold for more than a few hours gets flagged, because a forgotten hold is its own kind of failure. Second, the audit: once a day, check that no order shipped in the last twenty four hours had an open exception on it. A cron entry on any always-on machine runs both, and so does a free scheduled workflow, since the GitHub Actions schedule trigger costs nothing for a job this small. Send the clean run too, at least at first: a report that only speaks when something is wrong is a report you quietly stop believing.

BuildWhat runs itSetupRuns unattended?
The promptYou, in any AI chat tool, with a pasted inbox and order listMinutesNo
The scriptA webhook that reads the message and holds the fulfillmentAn afternoon, onceOn arrival
The scheduleThe same build plus a sweeper for stale holds and missed exceptionsA few extra minutesYes

Steal This Build

Here is the whole loop as a spec you can copy into your own stack this afternoon, or hand straight to a system that will turn the description into a running workflow for you.

  • Trigger: every inbound support message, read on arrival.
  • Classify: is it a change request, of what kind, and what exactly was asked for, copied verbatim.
  • Hold: if the fulfillment order is open, pause it immediately with a reason the warehouse can read.
  • Escalate: one exception record, one named owner, a two hour deadline, and a state that is either HELD or TOO_LATE.
  • Confirm: on close, verify the order actually matches what was requested, release the hold, and only then tell the customer it is done.

The shape is universal. Something arrives that invalidates work already in flight, the work and the message live in different systems, and the only thing standing between them is a person who has to notice in time. Swap the order for an invoice about to be sent, a contract about to go out for signature, or a campaign about to send, and the spec barely changes: catch the message, pause the handoff, give the decision an owner, verify the fix landed. That last step is the one everybody drops, and it is the one that turns a notification into something you can trust. It is the same discipline behind any build that has to stop and wait for a human decision automatically instead of hoping somebody is watching.

Build Your Version

Tell BYOBot about a loop in your week

Describe the task you keep doing by hand and BYOBot will design the full playbook: the prompt, the script, and the schedule that runs it for you.

Frequently Asked Questions

  • Not in the way customers mean. Order editing is built for changes made before fulfillment: you can add or remove line items, change quantities, and adjust shipping and discounts while the order is unfulfilled. Once a fulfillment exists, the package has a label and the carrier owns the address on it, so the fix stops being an edit and becomes a carrier intercept, a recall, or a reship. That is exactly why the useful automation runs in the minutes before fulfillment rather than after it, and why it belongs with the rest of what you put on autopilot around your store.
  • A notification tells somebody that a thing happened and then it is finished. An exception is a record with a state, an owner, and a deadline, and it stays open until a person or a rule closes it. Most order-change workflows fail because they are built as notifications: a Slack message fires, everybody sees it, nobody owns it, and the order ships unchanged. Build the exception instead, with a hold on the fulfillment so the clock stops while the decision is being made.
  • No, and this is the line worth holding. The automation should hold the fulfillment, extract what the customer asked for, and raise the exception. It should not change quantities, prices, or refunds on its own, because a hold is reversible and a money movement is not. Holding is cheap to undo and it buys the only thing you actually need: time for a person to decide while the order is still catchable.
  • For one step only. Reading a free-text customer email and working out that it is an address change for order 10482 is genuinely a language problem, and a model is the right tool for it. Everything after that is plain API work with no model involved: look up the fulfillment order, apply the hold, write the exception record, send the acknowledgment. Keeping the model on the reading step and off the acting step is what makes the build predictable, and it is the same split you want anywhere you hand inbound support work to a workflow.
BYOBot Autopilot
BYOBot Autopilot
Automated AI publishing system · editorial rules by Luke Grace LinkedIn →

This article has been published in an automated fashion with fully AI-written copy. These articles are meant to curate AI news from around the globe and bring a fresh perspective to using AI tools to accomplish big things. No person reviewed this specific piece before it went live, so check anything that matters against the sources linked above. Luke Grace sets the rules the system writes to. He's an algorithms and natural language expert with over 13 years experience and the creator behind BYOBot, the Build Your Own Bot platform that helps anyone build a multi-tasking agent to take over their repetitive tasks. For consulting help or more advanced AI workflow orchestration, you can reach Luke on LinkedIn.