Cancellation, return and refund as one processAll articles

Cancellation, return and refund as one process

A refund without a recorded case is a loss without evidence. This case shows the chain from cancellation via return and refund to the credit note.

Published: 2026-09-12Reading time: 5 mintapinomahub API & workflows
API & processesAPILogistics & inventory

A customer withdraws, one part comes back damaged, another does not fit. Three different cases that in daily practice often vanish into the same credit note. At month end neither the stock nor the accounts add up, and nobody can say which refund belonged to which return.

Cancellation, return and refund as one processInput: a customer changed their mind, or the goods are back on the yard 1. Cancel before dispatch (POST /commerce/v1/cancellations): reasonCode for the cancellation, quantities per line; the quantity is cancelled, not the order wholesale 2. Record the return (POST /commerce/v1/returns): receivedAt separates an announced return from an arrived one 3. Refund (POST /commerce/v1/refunds): amount with amountMinor and currency, bound to salesOrderId; returnId optional 4. Pull the credit note (GET /commerce/v1/credit-notes): Credit notes referencing the invoice (invoiceId) and the order (salesOrderId) Output: a refund attributed to the order and, where given, to the return A refund references the order and optionally, via returnId, the return. A refund without a case is a loss without evidence.Cancellation, return and refund as one processInput: a customer changed their mind, or the goods are back on the yard01Cancel before dispatchPOST /commerce/v1/cancellationsreasonCode for the cancellation, quantities per line; the quantity is cancelled, not the orderwholesale02Record the returnPOST /commerce/v1/returnsreceivedAt separates an announced return from an arrived one03RefundPOST /commerce/v1/refundsamount with amountMinor and currency, bound to salesOrderId; returnId optional04Pull the credit noteGET /commerce/v1/credit-notesCredit notes referencing the invoice (invoiceId) and the order (salesOrderId)Output: a refund attributed to the order and, where given, to the returnA refund references the order and optionally, via returnId, the return. A refund without a case is a losswithout evidence.
Four calls of the reversal. The refund hangs off the order and, where given, off a recorded return.

The contract therefore separates the three cases and links them by identifiers: the refund always references the order and, when returnId is set, the return. Every recorded refund can thus be attributed to an order, and to the return where one is set — backwards as well as forwards.

SurfaceRoles
CommerceParts trading, Vehicle trading

What this case requires

  • An order with lines. Cancelling and taking back happen per line and quantity, not wholesale; a refund is an amount against the order.
  • A time of arrival. An announced return is something other than an arrived one; receivedAt records the arrival. The contract does not tie the refund to this field.
  • Reasons per case. Withdrawal, transport damage and wrong order are three reasons with three consequences for stock.
  • Accounting that processes credit notes. Credit notes stand separate from the invoice and reference invoice and order; they contain no reference to the refund or the return.

The sequence

The table names the responsible call per stage and what exists afterwards. The reasoning for why a stage cannot be skipped follows below it.

The call chain of this use case
StageCallWhat exists afterwards
Cancel before dispatchPOST /commerce/v1/cancellationsreasonCode for the cancellation, quantities per line; the quantity is cancelled, not the order wholesale
Record the returnPOST /commerce/v1/returnsreceivedAt separates an announced return from an arrived one
RefundPOST /commerce/v1/refundsamount with amountMinor and currency, bound to salesOrderId; returnId optional
Pull the credit noteGET /commerce/v1/credit-notesCredit notes referencing the invoice (invoiceId) and the order (salesOrderId)

Why each stage is needed

  1. Cancel before dispatch. POST /commerce/v1/cancellations takes salesOrderId, reasonCode and the lines with quantities. As long as nothing has left the building this is the cheapest route — no return arises that nobody wants to pay for.
  2. Record the return. POST /commerce/v1/returns carries receivedAt. This field separates the announcement from the fact. The contract does not tie the refund to this field.
  3. Refund. POST /commerce/v1/refunds takes salesOrderId, amount with amountMinor and currency, and reasonCode; returnId is optional. Where the refund belongs to a return, that binding should be set via returnId, because the contract does not enforce it: a refund without a case cannot be explained to anybody later.
  4. Pull the credit note. GET /commerce/v1/credit-notes lists credit notes, separate from the invoice; each references the invoice via invoiceId and the order via salesOrderId. The contract provides no reference to the refund itself in the credit note; it shares only the salesOrderId with it.
Book a refund against a recorded return
curl -X POST \
  -H 'X-Api-Key: <API_KEY>' \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: erstattung-4711-ruecksendung-1' \
  -d '{"salesOrderId":"<salesOrderId>","returnId":"<returnId>","amount":{"amountMinor":8900,"currency":"EUR"},"reasonCode":"return"}' \
  'https://commerce-preview.invalid/commerce/v1/refunds'

What you end up with

In the end every recorded refund is attributed to an order via salesOrderId, and every credit note references invoice and order via invoiceId and salesOrderId. A refund created with returnId can be traced back to its return.

Where to find this in the documentation

The binding field lists, error codes and sample responses live in this surface’s OpenAPI contract at docs.tapinomahub.com (tapinoma-commerce). All use cases arranged by surface and role: overview of the use cases.

Frequently asked

Why not simply cancel and be done?

Because a cancellation before dispatch is something other than a return afterwards. The first does not touch stock, the second does — and only the second needs a goods-in inspection.

What if the customer announces a return but nothing arrives?

Then there is a case without an arrival. The receipt time receivedAt then stays empty; the contract does not tie the refund to this field, and whether to refund is your decision.

Can I refund partially?

Yes. The refund carries an amount and is bound to the order, optionally also to the return; the order’s payment status includes partially_refunded. Refunds are not yet activated in the contract.