Zid's Reverse Orders APIs should be integrated as a durable workflow, not as one "return" request. Product eligibility, financial calculation, refund initiation, bank-transfer evidence, reverse shipping and physical inspection are separate transitions. The safe design stores every transition, prevents duplicate side effects and reconciles money and inventory independently. This guide is for developers building ERP, WMS, customer-service or accounting integrations for Zid stores.
This is a practical guide, not a news report. Zid's documented endpoint behavior is stated as fact and linked below. The state machine, retry policy and reconciliation controls are engineering recommendations. The documentation was verified on October 23, 2026.
The four records you must not collapse
A return touches four different facts:
- The original order proves what was sold and the remaining quantity that can still be returned.
- The reverse order records the merchant's return intent, selected lines, location, reason and logistics data.
- The refund records the financial action and its payment method.
- The inspection result records what physically arrived in good condition, arrived damaged or never arrived.
If an ERP stores all four as one boolean named \returned\, it cannot answer whether money moved before the parcel arrived, whether a damaged unit was restocked, or whether a retry created a second refund.
What Zid documents
Before a partial return, call Zid's View for Return endpoint. It returns only products with remaining returnable quantities and recalculates totals after previous returns. A fully reversed order returns no products and a zero order total.
Next, the Calculate Reverse Totals endpoint previews subtotal, discounts, VAT and total. Zid explicitly documents this calculation as read-only: it does not create a reverse order, move stock, create a refund or update the order status.
The Create Reverse Orders endpoint persists the reverse request. It accepts the order, partial/full choice, inventory location, return reason, products and shipping information. Its response exposes the reverse-order identifier, selected lines, calculated totals and available refund methods.
The Create Refund endpoint is a separate financial step. Zid instructs clients to read \refund_total\ and \available_refund_payment_methods\, then choose an amount and valid method. For \zid_bank_transfer\, the receipt upload endpoint is mandatory and accepts image files after the refund exists.
Physical handling is separate again. The Update Return Products endpoint records \received_quantity\, \not_received_quantity\ and \damaged_quantity\. For each line, their sum must not exceed \reversed_quantity\; quantities are non-negative and at least one must be greater than zero. Zid documents the update as atomic: one invalid line fails the whole request.
Finally, the Reverse Orders Waybill endpoint creates a return label and may return label, tracking URL, tracking number, courier and service-level fields.
Recommended internal state machine
Do not mirror an external status into one mutable column. Keep a local return case with explicit milestones:
| Internal state | Evidence required | Side effect allowed |
|---|---|---|
\DRAFT\ | Original order and remaining quantities | None |
\QUOTED\ | Calculation input hash and totals snapshot | Customer/operator approval |
\REVERSE_CREATED\ | Zid reverse-order ID | Waybill request |
\REFUND_REQUESTED\ | Refund ID, amount and method | Receipt upload when required |
\IN_TRANSIT\ | Tracking number or manual-return evidence | Tracking updates |
\INSPECTED\ | Good, damaged and missing quantities per line | Inventory disposition |
\RECONCILED\ | Money, stock and order checks all pass | Close case |
The order of logistics and refund approval depends on merchant policy. Zid exposes separate operations; that does not mean your system must approve every financial effect immediately. High-value or fraud-sensitive returns may require inspection approval before the refund call. Consumer-policy and payment-provider obligations still apply.
Architecture: command, effect and reconciliation
Use three durable tables or equivalent records:
- \
return_cases\: original order ID, Zid reverse ID, state, requested and approved amounts, refund method and version. - \
return_lines\: original line ID, requested quantity, reversed quantity, received-good, damaged and not-received quantities. - \
return_effects\: operation name, request hash, started time, external ID, response snapshot, result and reconciliation state.
Your public API should accept an internal idempotency key. Even if the Zid endpoint does not document native idempotency for a write, repeated client requests can return the existing local case instead of issuing another external effect.
async function requestReturn(command: ReturnCommand) {
return db.transaction(async (tx) => {
const existing = await tx.returnEffects.find(command.idempotencyKey);
if (existing) return existing.publicResult;
const eligible = await zid.viewForReturn(command.orderId);
validateRemainingQuantities(command.lines, eligible.products);
const quote = await zid.calculateReverseTotals(command.orderId, command.lines);
await tx.returnEffects.insert({
key: command.idempotencyKey,
operation: "create_reverse_order",
requestHash: stableHash(command),
quoteSnapshot: quote,
status: "prepared"
});
return { status: "awaiting_approval", quote };
});
}Do not keep a database transaction open while waiting on a network call in production. The example highlights the records; a real implementation should use a short transaction to persist a command, then an outbox worker to call Zid and persist the result.
Handle unknown outcomes safely
A timeout does not prove failure. Zid may have accepted a write while your client lost the response. Retrying a refund blindly can duplicate money movement.
For every write:
- Persist \
started\before the call. - Store the exact request hash, not access tokens or unnecessary personal data.
- On a definite validation error, mark it rejected and do not retry unchanged input.
- On timeout or connection loss, mark the effect \
unknown\. - Reconcile against available reverse-order, order, credit-note or payment evidence before another write.
- Escalate unresolved financial uncertainty to an operator with the original request and observed evidence.
If an API does not expose enough evidence to distinguish success from failure, automated retry is not safe. A manual queue is better than a duplicated refund.
Money and inventory need different ledgers
Refund amount and restock quantity are related but not identical. A damaged product may be refunded but must not return to sellable stock. A parcel may be missing while the customer-service team has already approved a goodwill refund.
Model inventory disposition explicitly:
| Inspection result | Financial path | Inventory path |
|---|---|---|
| Received in good condition | Refund according to policy | Restock after SKU/location verification |
| Received damaged | Refund or review according to policy | Quarantine, repair or write-off |
| Not received | Hold or investigate | No restock |
| Quantity mismatch | Partial approval or review | Reconcile per line |
Never increment ERP stock merely because a reverse order was created. Use the physical inspection result and confirm which system owns the stock mutation. If Zid and the ERP can both adjust inventory, define one authority and import the other side's result; otherwise the same unit can be added twice.
Price, tax and rounding rules
Use Zid's calculated invoice lines and total as the platform quote. Do not reconstruct a refund from the current catalog price: discounts, VAT, line additions and previous returns may change the eligible amount.
Store monetary values as decimal amounts plus currency, and preserve the response snapshot that justified approval. Compare using currency precision, not binary floating-point equality. Before calling the refund endpoint, verify that the requested amount is not greater than the documented \refund_total\ and that the method appears in \available_refund_payment_methods\.
Security and privacy controls
- Request only the required \
orders.read_write\scope and keep manager credentials out of logs and analytics. - Treat receipt images as untrusted uploads: limit size and type, scan them, store them privately and restrict retention.
- Minimize customer address and phone replication; logistics services should receive only what the return requires.
- Separate permission to create a reverse order from permission to release money or override inspection results.
- Audit operator, reason, before/after quantities, approved amount and external identifiers.
Observability and reconciliation
Track business invariants, not only HTTP status:
- cases stuck in each state and their age;
- \
unknown\external effects awaiting reconciliation; - requested amount versus Zid quote versus refunded amount;
- reversed quantity versus good, damaged and missing totals;
- waybills without movement and parcels received without inspection;
- stock adjustments without a matching inspected line;
- bank-transfer refunds missing their required receipt.
Run a scheduled reconciliation that compares open local cases with Zid evidence. Alert on mismatches; do not silently rewrite accounting history.
Best practices and anti-patterns
Best practices
- Refresh \
view-for-return\immediately before quoting a partial return. - Save external IDs and immutable response snapshots.
- Use an outbox, bounded retries and a dead-letter/manual-review queue.
- Make inspection a per-line decision with explicit stock disposition.
- Test partial returns, prior returns, damaged items, timeouts and duplicate commands.
Anti-patterns
- Retrying a refund after a timeout without reconciliation.
- Treating the reverse order as proof the parcel arrived.
- Recalculating VAT and discounts from today's product price.
- Updating sellable stock from the requested return quantity.
- Storing receipt images in a public bucket or logging manager tokens.
When not to automate the full workflow
A small store with rare, high-touch returns may be safer with operator-assisted processing and automated validation only. Digital products, services and custom-made goods may require a different eligibility model. If the ERP cannot represent damaged and missing quantities separately, fix the data model before enabling automatic restocking.
The reviewed Zid pages document endpoint behavior but do not establish one atomic transaction across return, refund, logistics and inventory, nor do they document a universal idempotency guarantee for every write. Design for partial completion and reconciliation.
Implementation checklist
- Map original order and line IDs without relying on SKU alone.
- Refresh remaining returnable quantities.
- Calculate and snapshot the platform refund quote.
- Obtain policy approval, then create one reverse order.
- Record refund and receipt evidence as separate effects.
- Create and monitor reverse logistics when required.
- Inspect every line and apply an explicit stock disposition.
- Reconcile money, inventory and order state before closure.
Related guides: Zid wallet reconciliation, Salla and Zid order state machines, recovering broken Zid webhooks, and the engineering article library.
Primary references
- Zid — Order Details: View for Return
- Zid — Calculate Reverse Totals
- Zid — Create Reverse Orders
- Zid — Create Refund for Reverse Order
- Zid — Upload Bank Transfer Receipt
- Zid — Update Return Products
- Zid — Create Reverse Orders Waybill
- Unsplash License
- Guilherme Mendes — licensed warehouse photograph
Official references
These references document the tools discussed. Examples and design decisions are illustrative and should be adapted to the project and its versions.
Prepared by: Noor Yasser
Working through a similar engineering challenge?
I help teams turn architecture decisions into a clear scope and dependable, reviewable implementation.




