# Shipment exception triage board for fulfillment ops

> A morning board where your team works every stuck, failed, and expired shipment, grouped by courier and sorted by how long each one has been silent.

- Workflow type: app
- Services: AfterShip, Gmail
- Categories: Operations, Customer Support
- Published: 2026-08-14

## What it does

- Pulls every problem shipment into one board: delivery exceptions, failed delivery attempts, expired trackings, and anything that has quietly stalled in transit
- Groups the cards into a column per courier and stamps each one with the number of days since the carrier last scanned it, so the oldest problems rise to the top
- Opens the full scan history for any shipment in one click, next to the buttons that actually resolve it: restart a dead tracking, close it out as lost or returned, or fix a wrong courier and bad customer details
- Sends a short apology and status note to the customer from your own inbox, without leaving the board
- Remembers who owns each shipment and the note they left, with a My queue filter so everyone can see what they are chasing

## What you'll need

- An AfterShip account with shipments already being tracked
- A Google account for the mailbox the customer notes should come from
- A short list of the couriers your team ships with, so the columns match how you actually work

## Prompt

Build me an exception triage board that our fulfillment ops team works out of every morning. It is the place we resolve problem shipments, not just a report about them, so every card needs the buttons that actually close the problem out.

The main view is a board that loads problem shipments from AfterShip List Trackings. Include anything tagged Exception, AttemptFail, or Expired, plus anything still tagged InTransit that has gone quiet, meaning its most recent checkpoint is older than a configurable stall threshold that defaults to 7 days. Group the cards into one column per courier, using the courier slug and name on each tracking, and show a count of open problems in each column header. Every card shows the tracking number, courier, order number if present, destination, customer name, current status, and a prominent days since last checkpoint badge calculated from the newest checkpoint timestamp. Sort each column so the largest days since last checkpoint appears first, and colour the badge to escalate as it grows, for example calm under 3 days, warning at 3 to 7 days, and urgent past 7 days. Keep the thresholds in one config object at the top of the code so they are easy to change.

Store an owner and a triage note per shipment in app storage, keyed by the AfterShip tracking id, since AfterShip itself does not hold this. The card shows the current owner and the first line of the note. Add a Claim button that assigns the logged in user as owner, an editable note field, and a My queue toggle that filters the board to shipments owned by the current user. Also give me a courier filter, a free text search over tracking number, order number, and customer name, and a plain count of everything currently on the board.

Clicking a card opens a detail panel that calls AfterShip Get Tracking by ID for the freshest data and renders the full checkpoint history as a vertical timeline, newest first, showing each checkpoint's time, status, location, and message. Above the timeline show the shipment summary: courier, tracking number, current status, whether the tracking is still active, expected delivery if known, the destination address, and the customer email and phone on file. The owner and triage note are editable in this panel too.

The detail panel carries the resolution actions. Retrack calls AfterShip Retrack Tracking by ID to restart a dead tracking. Close out opens a small confirmation that calls AfterShip Mark Tracking as Completed by ID with a reason the user picks from LOST or RETURNED_TO_SENDER, since those are the two outcomes this team closes with, and it should warn that this stops all further updates on that shipment. Fix details opens a form that calls AfterShip Update Tracking by ID so the team can correct a misdetected courier or fix the customer name, email, phone, and address. After any successful action, refresh that tracking from Get Tracking by ID so the card and timeline reflect the new state immediately.

Enforce the AfterShip retrack rules in the interface rather than letting the call fail. Retrack only works on an inactive or expired tracking and is allowed once per shipment. So enable the Retrack button only when the tracking is expired or no longer active, and only when this app has not already recorded a successful retrack for that shipment id. In every other case render the button greyed out with a tooltip giving the specific reason, for example that the shipment is still active so AfterShip will not restart it, or that it has already been retracked once and cannot be retracked again. Record each successful retrack in app storage so the once per shipment rule survives a page reload. If AfterShip still rejects a call, translate the provider codes into friendly messages: 4013 means retrack is only allowed on an inactive tracking, and 4016 means the shipment has already been retracked once. Mark as completed must always send one of the allowed reasons.

Add an Email customer button that opens a short composer prefilled with a brief apology and status note built from the shipment's current status, courier, and latest checkpoint, addressed to the customer email on the tracking. The user can edit the subject and body before sending, and sending goes through Gmail Send a Message. Log the send time and the sender against the shipment in app storage and show it on the card, so the team can see at a glance that a customer has already been contacted and does not get emailed twice.

A few implementation notes. List Trackings is cursor paginated, so page through using the next cursor and has next page values in the pagination data until the board has the full set of problem shipments. AfterShip is limited to 10 requests per second, so batch the initial load sensibly and avoid firing a detail request per card up front, since the board only needs the summary data until a card is opened. Show a clear loading state on first load, a refresh control so the team can pull the latest state mid morning, and a friendly empty state for when there are no exceptions left to work.

## How to customize

- Change how many quiet days it takes before a moving shipment counts as stalled, and when a card turns urgent
- Pick which columns appear and how they are ordered, for example putting your problem couriers first
- Reword the customer apology template so it matches your brand voice and support signature

## FAQ

### Does this replace our AfterShip account?

No. The board reads live from AfterShip and writes changes straight back to it, so AfterShip stays the source of truth. The board is simply a faster place to work through the problems each morning.

### Why is the Retrack button greyed out on some cards?

AfterShip only allows a tracking to be restarted when it has gone inactive or expired, and only once per shipment. When either rule blocks the action, the button is disabled and hovering it explains exactly why, so nobody wastes time on a click that would fail.

### Can two people work the board at the same time?

Yes. Each shipment stores an owner and a triage note, so you can see who is already chasing something before you pick it up. The My queue filter narrows the board to whoever is logged in.

### What happens to the customer emails we send?

They go out from the Google account you connect, so replies land in your normal inbox and the sent copy sits in your usual sent folder alongside everything else.

### Will it work if we use several couriers?

Yes, that is the point of the layout. Each courier gets its own column, which makes it obvious when one carrier is generating far more problems than the others.

Use this prompt in General Input: https://www.generalinput.com/prompts/shipment-exception-triage-board-for-fulfillment-ops