Series · 7 parts Published June 28, 2026

Return and RMA handler

A customer wants to send something back, and what follows is the same dull routine every time — check it’s still in the return window, issue an RMA number, print a prepaid label, wait for the parcel, inspect it, then decide between a refund and a replacement. This is the design of a small serverless system that runs that whole returns desk end to end: it checks the request against your policy, issues the RMA and the label, tracks the parcel on its way back, and once it’s received proposes refund or replacement with the reason attached. The eligibility and policy checks are plain code, and a human approves the money or the swap before anything moves. Seven posts on the same system — one diagram at a time — with an engineering reference at the end.

  1. 01

    A return and RMA handler on AWS for a few dollars a month

    The whole system on one page — a Step Functions state machine that runs request, eligibility, RMA and label, await inbound, inspect, and decide — plus the rule that a human approves every refund or replacement.

  2. 02

    How a return request gets checked

    How a return request is checked against policy — the order lookup, the plain-code checks for return window, non-returnable flags, condition, and prior returns — and why a fail is declined with the exact reason rather than guessed.

  3. 03

    How an RMA and label get issued

    How an approved request becomes an RMA number and a prepaid label — the unique RMA, the carrier label API call keyed from Secrets Manager, the label stored in S3, and the one email that tells the customer exactly what to do.

  4. 04

    How an inbound parcel gets tracked

    How the inbound parcel is tracked while the state machine waits — the paused execution holding a task token, the carrier webhook that resumes it on a real scan, and the scheduled sweep that catches parcels that never come back.

  5. 05

    How a refund or replacement gets decided

    How a refund or a replacement gets decided — the inspection that records the real condition, the plain-code decision that proposes refund or replace per policy with the reason attached, and the human who approves before anything moves.

  6. 06

    What the return and RMA handler costs

    A line-by-line monthly cost of about $2.90 for roughly 120 returns, where the money actually goes, why the Step Functions transitions and the carrier label API are the only things that scale, and what the bill looks like at ten times the volume.

  7. 07

    Engineering reference: the return and RMA handler architecture

    The same system drawn for engineers — the Step Functions state machine and its states, the Lambda inventory, the EventBridge rules and the sweep schedule, the DynamoDB returns table and key schema, S3, SES, IAM scope, and the region.

What is a return and RMA handler?
A small serverless system that runs the whole returns desk. A customer asks to send something back; it checks the request against your policy (the return window, the item’s condition, any non-returnable flags), issues an RMA number and a prepaid shipping label, tracks the inbound parcel by its tracking number, and once the parcel is received and inspected it proposes a refund or a replacement with the reason attached. It is distinct from a plain refund handler: it owns the full logistics — the RMA, the label, the tracking, and the refund-or-replace decision. A human approves the money or the replacement; it never does that on its own.
How much does it cost to run?
About $2.90/month at typical small-business volume — roughly 120 returns a month. The fixed cost is essentially zero because nothing runs while no one is returning anything. What scales with volume is the Step Functions state transitions (cents) and the carrier’s label API, which is an external fee on your courier contract rather than an AWS cost. The one real AWS fixed line is Secrets Manager, at $0.40 per secret per month for the label and webhook keys.
Which AWS services does it use?
Lambda (Python 3.14, arm64), AWS Step Functions (a Standard state machine for request → eligibility → RMA and label → await inbound → inspect → decide), EventBridge (carrier tracking webhooks and a Scheduler sweep for parcels not yet returned), DynamoDB on-demand for the returns table, S3 for labels and inspection photos, SES with Lambda Function URLs for the approve buttons, SQS with a dead-letter queue, Secrets Manager for the carrier and label API keys, CloudWatch Logs with 7-day retention, AWS Budgets, and Bedrock (Claude Haiku 4.5) optionally for the customer-facing wording. No API Gateway, no NAT Gateway, no always-on compute. One region, eu-west-2.
How is return eligibility decided?
By plain-code policy checks — no model on that path. The eligibility step looks up the order, then runs a short list of deterministic checks against the policy: is the purchase inside the return window, is the item flagged non-returnable (final sale, hygiene, perishable), has it already been returned, and is the declared condition allowed. Each check has a clear pass or fail, and the request only moves forward if every one passes. Anything that fails is declined with the exact reason, or escalated to a person where policy says a human should decide.
Does it use AI?
Only for wording, and only optionally. Bedrock Haiku 4.5 can be used to phrase the customer-facing emails — the RMA-and-label message and the final outcome — in your voice. The eligibility checks and the refund-or-replace decision are plain Python against your written policy; no model decides whether a return is allowed or whether money moves. Turn Bedrock off and the system still runs end to end on templated text.
Can it issue a refund on its own?
No. The system proposes a refund or a replacement with the reason attached — for example “item received, matches the order, sealed: propose full refund” or “received damaged in transit: propose replacement” — and a human on the returns desk approves before anything moves. The approver gets three choices: approve the proposal, switch it (refund instead of replace, or the reverse), or reject. Every action is logged. No money and no replacement leaves without a person signing off.
All posts