Docs Sellers

Adjustments

LiveUpdated

View as Markdown

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 a 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.

A refund made in your PSP’s own dashboard needs no call either: with a PSP connection, the PSP’s refund and cancellation webhooks become the same reversals.

How types map

ProtocolIts adjustments[].type valuesMapping to reversal.kind
UCP6: refund, return, credit, price_adjustment, dispute, cancellationOne to one; dispute ↔ chargeback_credit
ACP5One to one; chargeback_credit renders as dispute
Adyen Order API5, with status pending / completed / failedstatus maps to the reversal’s pending / completed / failed
Shopify8, of which 5 are reversals: refund, cancellation, return, exchange, order_editThose 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_signed under your key.
  • The buyer’s mandate account and budget are refilled according to the buyer’s refill_policy; you see the mandate_effect in the answer but never the buyer’s cap.
  • The buyer’s agent is told through the reversal.completed webhook and the reversals[] on its payment request.
  • Your reconciliation slice gains an adjustments_leg entry with source: merchant_webhook; when the buyer’s rail posts the refund, a second entry with source: rail matches it.

Interfaces

SurfaceCall
REST, sellersPOST /v0/sellers/adjustments, POST /v0/sellers/reversals, POST /v0/sellers/fulfillments, POST /v0/ucp/orders (order_updated, order_shipped), POST /v0/psp/{psp}/webhook/{connection_id}
REST, buyer sideGET /v0/reversals/{id}/adjustments?protocol=ucp|acp|adyen|shopify
SDKsellers.adjustments.report(body), sellers.reversals.request(body), sellers.fulfillments.confirm(body)
Console (seller)/orders/{id}: the adjustments table with the delivery state; /reversals