Docs · Sellers
Adjustments
LiveUpdated
Sellers. Written for merchants that receive agent orders.
UCP, ACP, Adyen and Shopify each have an adjustments[] notification, and none of them executes anything or says what the refund does to the buyer’s limit. Enruta reads your adjustment, decides and executes the reversal on the buyer’s side, and gives you the same reversal rendered in all four shapes.
Report an adjustment
POST /v0/sellers/adjustments Authorization: Bearer enruta_slr_…
{
"domain": "reamandrule.com",
"order_id": "ord_01M2512SM3V3A9R4EBJM8RRRV5",
"protocol": "ucp", // ucp | acp | shopify | adyen
"adjustment": { "id": "adj_01M2G8Y2K5T8W3Q6N9B1D4H7XR", "type": "refund", "amount": { "value": "9.99", "currency": "USD" },
"reason": "customer_request", "occurred_at": "2026-09-13T15:03:40Z", "status": "completed" },
"signature": "eyJhbGciOiJFUzI1NiIs…" // optional: your detached JWS over the adjustment
}
201 {
"reversal": { "id": "rev_01M2G8YV5R3T7W2Q9K4N8B6DXP", "kind": "refund", "stage": "settled", "status": "completed", "mandate_effect": "none", "reversal_record_id": "rec_01M2G8Z0Q4W7T2K9N5B3D6H1XC" },
"adjustments": {
"ucp": { "type": "refund", "amount": 999, "currency": "USD", "reason": "customer_request", "reference": "rev_01M2G8YV5R3T7W2Q9K4N8B6DXP" },
"acp": { "type": "refund", "amount": 999, "currency": "USD", "reason": "customer_request", "reference": "rev_01M2G8YV5R3T7W2Q9K4N8B6DXP" },
"adyen": { "pspReference": "rev_01M2G8YV5R3T7W2Q9K4N8B6DXP", "type": "refund", "status": "completed" },
"shopify": { "kind": "refund", "amount": "9.99", "currency": "USD", "reason": "customer_request" }
}
}The reversal is created with initiator: merchant, kind mapped from your protocol’s type, protocol_ref and dedupe_key = "<order_id>:<adjustment id>", so reporting the same adjustment twice creates one reversal. POST /v0/sellers/reversals takes the same body with execute semantics: Enruta drives the buyer’s rail when it can (the sandbox rail at once, Stripe Issuing on test keys); a refund you already made in your own PSP stays pending until the buyer’s rail posts it or you report status: completed.
Or let the order webhook do it
If your store already sends the UCP order webhook to Enruta, an order_updated event whose order carries new entries in adjustments[] reports each of them, deduplicated by order_id:adjustment.id; an order_shipped event (or a shipped event in fulfillment.events[]) confirms fulfillment. The reference merchant’s admin “Refund” and “Ship” actions work exactly this way.
How types map
| Protocol | Its `adjustments[].type` values | Mapping to `reversal.kind` |
|---|---|---|
| UCP | 6: refund, return, credit, price_adjustment, dispute, cancellation | One to one; dispute ↔ chargeback_credit |
| ACP | 5 | One to one; chargeback_credit renders as dispute |
| Adyen Order API | 5, with status pending / completed / failed | status maps to the reversal’s pending / completed / failed |
| Shopify | 8, of which 5 are reversals: refund, cancellation, return, exchange, order_edit | Those five map in; the three transaction-record types are not reversals |
What happens on the buyer’s side
- The reversal is decided against the buyer’s policy (amount within the original, stage, finality, window) and sealed as a linked record chained to the payment; when you signed the adjustment, the record’s subject is
third_party_signedunder your key. - The buyer’s mandate account and budget are refilled according to the buyer’s
refill_policy; you see themandate_effectin the answer but never the buyer’s cap. - The buyer’s agent is told through the
reversal.completedwebhook and thereversals[]on its payment request. - Your reconciliation slice gains an
adjustments_legentry withsource: merchant_webhook; when the buyer’s rail posts the refund, a second entry withsource: railmatches it.
Interfaces
| Surface | Call |
|---|---|
| REST, sellers | POST /v0/sellers/adjustments, POST /v0/sellers/reversals, POST /v0/sellers/fulfillments, POST /v0/ucp/orders (order_updated, order_shipped) |
| REST, buyer side | GET /v0/reversals/{id}/adjustments?protocol=ucp|acp|adyen|shopify |
| SDK | sellers.adjustments.report(body), sellers.reversals.request(body), sellers.fulfillments.confirm(body) |
| Console (seller) | /orders/{id}: the adjustments table with the delivery state; /reversals |
Planned: adapters that read Adyen’s Order API and Shopify’s orders/updated for you (Adyen and Checkout.com January 2027; Shopify October 2026), so a refund made in your PSP’s dashboard becomes a reversal without a call from your code.