Returns reconciliation reference
A compact reference for how SKU.io reconciles return receipts against RMAs, what each disposition does to inventory and the ledger, and how each marketplace channel behaves. For the narrative version, see How returns reconciliation works.
Receipt reconciliation states
Every return receipt carries a reconciliation state that says whether — and how confidently — it's tied to an RMA.
| State | Meaning |
|---|---|
| matched | The receipt is linked to an RMA. Any receipt that has an rma_id is forced to this state. |
| blind_unmatched ("Unmatched") | A blind receipt (no RMA) that hasn't been linked yet. |
| needs_review | More than one plausible RMA/receipt match was found, so the system refused to auto-link. A human must resolve it. |
Disposition → inventory & accounting effect
The disposition chosen at receive time is what determines both the inventory movement and whether an accounting journal posts.
| Disposition | Inventory | Accounting journal |
|---|---|---|
Add to Stock (added_to_stock) | Restocks the original SKU as a new FIFO layer. Returned units restock as owned, even if the original stock was consignment. | Posts Dr Inventory / Cr COGS. |
New Blemished SKU (new_blemished_sku) | Restocks a separate blemished SKU as a new FIFO layer. | Posts no journal line. |
Discard (discarded) | Adds nothing back. | No journal line. |
New Blemished SKU puts units back on the shelf (a new FIFO layer on the blemished SKU) but does not post an accounting entry. Only Add to Stock posts to the ledger (Dr Inventory / Cr COGS). If you reconcile inventory value against the ledger, blemished restocks will show as inventory with no corresponding journal.
Which reconciliation engine runs
When a blind receipt meets a marketplace RMA, one of two engines links them. Which one depends on whether the RMA already has line items.
| Situation | Engine | What it does |
|---|---|---|
| A marketplace refund already created an RMA with lines, then a blind receipt arrives | ReturnReconciliationService | Maps the receipt lines onto the existing RMA lines and records quantity. Adds no new movement. |
| A header-only marketplace RMA (no lines) + a matching blind receipt | BlindReceiptMatchService | Mirrors the receipt's lines into new RMA lines. |
Both engines claim a receipt atomically, so two processes can't both attach the same receipt, and both work within a 30-day lookback. They differ on which RMA statuses they'll touch:
- ReturnReconciliationService (lined RMAs) only considers receivable RMAs — Approved, In Transit, or Partially Received (never Draft) — so it won't link out from under a draft a human is still editing.
- BlindReceiptMatchService (header-only RMAs) heals any non-terminal RMA, including Draft. This is deliberate: the Returns Inbox matcher creates a Draft header-only RMA and immediately heals it from the blind receipt.
Marketplace channel behavior
How each channel turns a marketplace return into an RMA, and whether that RMA surfaces in the Returns Inbox.
| Channel | How returns become RMAs | In the Returns Inbox? |
|---|---|---|
| Shopify | A refund with restock_type=return, or a Shopify Return object → RMA. Can auto-receive if the instance's auto-receive-refunded-returns setting is on (default on). | Yes |
| Amazon MFN | AmazonReturnManager builds the RMA directly. | No |
| Amazon FBA | One RMA per order, created already Closed (restocked at Amazon; no physical receipt). Only sellable dispositions create RMAs. | No |
| Walmart | Persisted, then linked by the shared matcher. | Yes |
| Trackstar | Persisted, then linked by the shared matcher. | Yes |
| TikTok Shop | The translator creates the RMA directly. | No |
Behavior when default_return_warehouse_id is unset
If no Default Returns Warehouse is configured, channels diverge — some hard-stop, some create an RMA with no warehouse. Call this out because it's inconsistent.
| Channel | If no default returns warehouse is set |
|---|---|
| Shopify | Hard stop — no RMA is created. |
| TikTok | No RMAs created. |
| Amazon MFN | RMA created with a null warehouse. (FBA is unaffected — it resolves the Amazon fulfillment-center warehouse, not the default returns warehouse.) |
| Walmart | Return-center step degrades silently. |
Always set a Default Returns Warehouse under Settings → Returns so no channel silently drops or half-creates a return.
Idempotency keys
Re-syncing a channel never duplicates an RMA, but the key that guarantees this differs per channel.
| Channel / path | Idempotency key |
|---|---|
| Shopify / TikTok | The channel return id stored on the RMA. |
| Amazon MFN | The return's linked RMA. |
| Amazon FBA | One RMA per order. |
| Inbox matcher (Shopify / Walmart / Trackstar) | The external source + external return id. |
Related
- How returns reconciliation works — the narrative walkthrough of this pipeline.
- RMA status reference — the RMA lifecycle and receive dispositions.
- Link unmatched (blind) returns — resolving
blind_unmatchedandneeds_reviewreceipts by hand. - Match marketplace returns — working the Returns Inbox.
- Set up return disposition policies — automating the disposition choice.