Part 4 of 7 · Return and RMA handler series ~6 min read

How an inbound parcel gets tracked

Between issuing a label and getting the box back, the system has nothing to do but wait — and waiting well is harder than it sounds. This post is about the await-inbound step: how a Step Functions execution pauses cheaply for days, how a real carrier scan wakes it back up, and how a daily sweep makes sure a parcel that never ships doesn’t sit open forever.

Key takeaways

  • After the label goes out, the state machine pauses on an “await inbound” step that can wait for days at no cost.
  • The paused execution holds a task token, stored on the return and findable by the parcel’s tracking number.
  • A real carrier scan arrives as a webhook, is routed through EventBridge, and resumes the exact waiting execution.
  • A daily EventBridge Scheduler sweep catches parcels that were never sent, so a return never sits open forever.
  • The wait ends on a genuine delivered scan — never on a guess that the box probably arrived.

Waiting well

Between handing the customer a label and getting the box back, there’s nothing to do but wait — and that waiting is where naive systems either burn money or lose track. You don’t want a Lambda sitting spinning for a week, and you don’t want to poll the carrier every hour for a parcel that hasn’t moved. Step Functions handles this properly: the execution reaches an await inbound step, hands out a task token, and goes to sleep. It costs nothing while it sleeps — Step Functions bills state transitions, not the days a parcel spends in a van — and it wakes only when something real happens.

Two things can wake it: a carrier scan that says the parcel was delivered back to you, or a scheduled sweep that decides the parcel is never coming.

The await-inbound step: a paused execution woken by a carrier webhook or a scheduled sweep At the top, a Carrier box represents the courier scanning the inbound parcel. Inside the AWS account container, a webhook chain runs left to right: a Tracking webhook on a Lambda Function URL receives the scan, passes it to an EventBridge bus called rmar-events, and a rule triggers the rmar-track Lambda. The rmar-track Lambda reads the rmar-returns table by the parcel’s tracking number (a GSI) to find the stored task token, then issues SendTaskSuccess to a paused Step Functions step labelled “Await inbound” that holds the task token. When resumed, the execution continues to the Inspect stage. Below, a separate path: an EventBridge Scheduler runs the rmar-sweep Lambda daily; the sweep finds parcels past the return window that never shipped and times the waiting execution out. A note states the wait costs nothing while it lasts because Step Functions bills transitions, not the days a parcel spends in transit. Carrier scans the inbound parcel AWS account Tracking webhook Lambda Function URL EventBridge bus rmar-events rmar-track match + resume rmar-returns GSI tracking_no find token Await inbound (paused) holds the task token SendTaskSuccess → Inspect (Part 5) EventBridge Scheduler daily rmar-sweep parcels past the window time out The wait costs nothing while it lasts — Step Functions bills transitions, not days in transit.
Fig 4. The inbound wait. A paused execution holds a task token; a real carrier scan routes through EventBridge to rmar-track, which finds the token by tracking number and resumes the exact return. A daily sweep times out parcels that never shipped.

The paused execution

When rmar-label finishes, the state machine moves to a task step configured to wait for a task token. Step Functions generates the token and the step hands it off — the function writes it onto the return record, alongside the tracking number from Part 3 — then the execution simply parks. There’s no compute running, no queue being drained, nothing being polled. The whole return is now represented by one sleeping execution and one row in rmar-returns that says, in effect, “when tracking number XYZ is delivered, resume with this token.”

The carrier scan that wakes it

Carriers will post tracking events to a webhook if you register one — collected, in transit, out for delivery, delivered. The handler behind the rmar-track Function URL takes each event, verifies it against a signing secret from Secrets Manager, and publishes it onto an EventBridge bus, rmar-events. A rule on that bus — matching only the events that matter, the “delivered to the return address” ones — triggers rmar-track. It looks up the return by tracking number using a GSI, reads the stored task token, and calls SendTaskSuccess with the scan details. That, and only that, resumes the execution, which moves straight on to the inspect stage. Putting EventBridge in the middle means the noisy in-transit scans are filtered out cheaply and the only thing that ever wakes a return is the scan that genuinely matters.

The sweep for parcels that never come

Plenty of returns are requested and never sent — the customer changes their mind, or the label sits in their inbox until they forget. Those executions would otherwise wait forever. rmar-sweep, fired daily by EventBridge Scheduler, scans for returns still parked past a sensible deadline — say 21 days after the label was issued — and resolves them: a gentle reminder a few days in, and a clean timeout that closes the return at the deadline so it isn’t left dangling. A timed-out return is never refunded; it’s simply closed, because nothing came back. The sweep is also where a stuck-in-transit parcel gets noticed and handed to a person, so a return that’s genuinely lost in the post gets a human rather than silence.

Design rules for the inbound wait

  • Pause, don’t poll. The execution sleeps on a task token; nothing runs and nothing is billed while a parcel travels.
  • Wake on a real scan. Only a genuine delivered event resumes a return — never an assumption that it arrived.
  • Filter at EventBridge. In-transit noise is dropped by the rule; only the delivered scan reaches the resume function.
  • Find it by tracking number. The GSI on the returns table ties a scan back to the one execution waiting on it.
  • Sweep the strays. A daily timeout closes returns that never shipped — closed, not refunded — and flags the genuinely lost.
All posts