Refunds

Introduction

DJUST PAY supports refunding payments on orders — either fully or partially. This page explains how refunds work, how they are funded, their impact on commissions and supplier payouts, and how to retrieve the refund history of a logistic order.


Key Concepts

Full Refund

A full refund reimburses the entire order amount to the buyer. The payment status of the order transitions to REFUNDED.

Partial Refund

A partial refund reimburses a specific amount (less than the order total) to the buyer. Multiple partial refunds can be issued on the same order, up to the total order amount. The payment status of the order reflects the partial refund state until the full amount is refunded.

Refund Funding

Refunds are funded from the supplier balance account. If the supplier's balance is insufficient, the configured funding policy at the tenant level determines whether the marketplace balance account can cover the difference.

This mechanism is identical for both full and partial refunds.

Refund Reason

When initiating a refund, an optional reasonCode can be provided to record why the refund was requested (e.g. CUSTOMER_REQUEST, ORDER_ERROR). The reason is persisted for both full and partial refunds and is returned in the refund history.

Refund History

Every refund requested on a logistic order — whether it succeeded or failed — is recorded and can be retrieved through a dedicated endpoint, with its amount, reason, mode, status, dates and PSP reference. A failed refund does not prevent a new refund from being requested on the same logistic order.


Typical Workflow

flowchart LR
  %% Styles (Readme)
  classDef create   fill:#e8f1ff,stroke:#2f6feb,stroke-width:2px,color:#0b3d91;
  classDef read     fill:#ede9fe,stroke:#7c3aed,stroke-width:2px,color:#1e1b4b;
  classDef update   fill:#e0f7fa,stroke:#06b6d4,stroke-width:2px,color:#0c4a6e;
  classDef add      fill:#ecfdf5,stroke:#10b981,stroke-width:2px,color:#064e3b;
  classDef remove   fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d;
  classDef decision fill:#fff4e5,stroke:#f59e0b,stroke-width:2px,color:#7a3e00;
  classDef place    fill:#dcfce7,stroke:#16a34a,stroke-width:2px,color:#14532d;
  classDef sys      fill:#f2f4f7,stroke:#475569,stroke-width:2px,color:#111827;
  classDef ok       fill:#ecfdf5,stroke:#10b981,stroke-width:2px,color:#064e3b;
  classDef stop     fill:#fee2e2,stroke:#ef4444,stroke-width:2px,color:#7f1d1d;

  A["📘 Operator triggers refund<br>POST /v1/logistic-orders/id/refunds"]:::create
  B{{"💰 Amount specified?"}}:::decision
  C["🔄 Partial refund<br>Specified amount"]:::update
  D["🔄 Full refund<br>Total order amount"]:::update
  E{{"💳 Supplier BA<br>sufficient?"}}:::decision
  F["✅ Funded from<br>supplier BA"]:::place
  G{{"🏦 Marketplace<br>funding policy?"}}:::decision
  H["💰 Marketplace BA<br>covers difference"]:::add
  I["⚠️ Refund blocked<br>Insufficient funds"]:::stop
  J["✅ Refund processed<br>Commission recalculated"]:::place

  A --> B
  B -->|Yes| C
  B -->|No| D
  C --> E
  D --> E
  E -->|Yes| F --> J
  E -->|No| G
  G -->|Enabled| H --> J
  G -->|Disabled| I

  style A rx:8,ry:8
  style C rx:8,ry:8
  style D rx:8,ry:8
  style F rx:8,ry:8
  style H rx:8,ry:8
  style I rx:8,ry:8
  style J rx:8,ry:8

API Reference

Initiate a refund

Endpoint: POST /v1/logistic-orders/{logisticOrderId}/refunds — operationId: ADM-ORDER-100

HeaderRequiredDescription
dj-clientYesOPERATOR
dj-api-keyYesAPI key

Request body

FieldTypeRequiredDescription
amountnumberNoGross amount to refund. If omitted, a full refund is performed.
reasonCodestringNoReason for the refund (e.g. CUSTOMER_REQUEST). Persisted for both full and partial refunds, and returned in the refund history.

Partial refund example

{
  "amount": 25.50,
  "reasonCode": "CUSTOMER_REQUEST"
}

Full refund example

{}

Tip: The reasonCode is optional in every mode — a refund without a reason works exactly as before. Providing one makes the refund history much easier to exploit.

Response

  • 200 OK — refund successfully initiated.

List the refunds of a logistic order

Endpoint: GET /v1/logistic-orders/{logisticOrderId}/refunds — operationId: ADM-ORDER-553

Returns the paginated refund history of a logistic order, with one entry per refund requested on it. An order refunded several times returns several entries; an order that has never been refunded returns an empty list.

HeaderRequiredDescription
dj-clientYesOPERATOR
dj-api-keyYesAPI key

Query parameters

ParameterRequiredDescription
idTypeNoDJUST_ID (default): logisticOrderId is the DJUST business ID. EXTERNAL_ID: it is an external ID.
pageNoPage number (0-based). Default: 0
sizeNoItems per page. Default: 20, min 1, max 100
sortNoFormat property:(asc|desc). Sortable property: createdAt. Default: createdAt:desc

Refund entry fields

FieldDescription
refundIdIdentifier of the refund
createdAtWhen the refund was requested
executedAtWhen the refund was processed
amount / currencyRefunded amount and currency
reasonCodeReason supplied when the refund was requested (if any)
refundModeRefund mode (e.g. FREE_AMOUNT for a partial refund by amount)
statusCurrent status of this individual refund (see below)
pspReferenceReference of the refund at the payment provider
failureReasonReason of the failure, for refunds ending in FAILED or INSUFFICIENT_FUNDS

Refund statuses

StatusMeaning
CREATED / PENDINGTransient — the refund is being processed by the payment provider. Overwritten by the final status once processing completes.
REFUNDEDThe refund was successfully processed.
FAILEDThe refund failed — see failureReason.
INSUFFICIENT_FUNDSThe refund could not be funded — see failureReason.
📘

Note: A refund that ends in FAILED or INSUFFICIENT_FUNDS does not prevent a new refund from being requested on the same logistic order.

Example response

{
  "content": [
    {
      "refundId": "d1eebc99-9c0b-4ef8-bb6d-6bb9bd380a02",
      "createdAt": "2026-04-02T10:00:00Z",
      "executedAt": "2026-04-02T10:05:00Z",
      "amount": 20.0,
      "currency": "EUR",
      "reasonCode": "ORDER_ERROR",
      "refundMode": "FREE_AMOUNT",
      "status": "FAILED",
      "pspReference": "MT8G4LN6FBKGK6R3",
      "failureReason": "Refund webhook returned success=false"
    },
    {
      "refundId": "d1eebc99-9c0b-4ef8-bb6d-6bb9bd380a01",
      "createdAt": "2026-04-01T10:00:00Z",
      "executedAt": "2026-04-01T10:05:00Z",
      "amount": 30.0,
      "currency": "EUR",
      "reasonCode": "CUSTOMER_REQUEST",
      "refundMode": "FREE_AMOUNT",
      "status": "REFUNDED",
      "pspReference": "MT8G4LN6FBKGK6R2",
      "failureReason": null
    }
  ],
  "empty": false,
  "first": true,
  "last": true,
  "number": 0,
  "numberOfElements": 2,
  "size": 20,
  "sort": ["createdAt:desc"]
}

Errors

  • 400 — invalid pagination parameters (F-E-008 if size is less than 1, F-E-010 if size exceeds 100).
  • 404 — the logistic order does not exist.

Business Rules

RuleDescription
Partial refundThe amount field specifies the refund amount. Multiple partial refunds can be issued on the same order.
Cumulative limitThe total of all partial refunds cannot exceed the original order amount.
Commission adjustmentThe marketplace commission is recalculated proportionally to the refunded amount.
Funding sourceRefunds are funded from the supplier balance account. If insufficient, the marketplace balance account may cover the difference based on the tenant's funding policy.
Payout impactA partially refunded order remains eligible for supplier payout, with the payout amount adjusted to account for the refund.
Reason persistenceThe optional reasonCode supplied at initiation is persisted for both full and partial refunds, and returned in the refund history.
Failed refundsA refund ending in FAILED or INSUFFICIENT_FUNDS is kept in the history with its failureReason, and does not prevent a new refund on the same logistic order.

Sequence Diagram

sequenceDiagram
    participant Operator
    participant DJUST PAY
    participant PSP

    Operator->>DJUST PAY: POST /v1/logistic-orders/{logisticOrderId}/refunds (dj-client: OPERATOR)
    DJUST PAY->>DJUST PAY: Validate refund amount against order total
    DJUST PAY->>DJUST PAY: Check supplier BA balance

    alt Sufficient funds in supplier BA
        DJUST PAY->>PSP: Trigger refund from supplier BA
    else Insufficient funds and marketplace funding enabled
        DJUST PAY->>PSP: Transfer from marketplace BA to supplier BA
        DJUST PAY->>PSP: Trigger refund from supplier BA
    end

    PSP-->>DJUST PAY: Webhook: refund confirmed
    DJUST PAY->>DJUST PAY: Update payment status and recalculate commission
    DJUST PAY-->>Operator: 200 OK

Best Practices

  1. Start with partial refunds — if the buyer only needs a partial reimbursement, use the amount field to avoid refunding the full order.
  2. Check the order's refund history — before issuing a new partial refund, retrieve the refunds already requested with GET /v1/logistic-orders/{logisticOrderId}/refunds (ADM-ORDER-553) and verify the cumulative amount already refunded to avoid exceeding the order total.
  3. Monitor funding policy — if your marketplace funding policy is disabled, ensure supplier balance accounts are adequately funded before triggering refunds.
  4. Commission tracking — after a partial refund, the marketplace commission is proportionally reduced. Monitor your commission reports accordingly.
  5. Always provide a reasonCode — the reason is persisted on both full and partial refunds and returned in the refund history, making audits and customer support much easier.
  6. Do not treat CREATED / PENDING as final — these statuses are transient. Poll the refund history until the refund reaches REFUNDED, FAILED or INSUFFICIENT_FUNDS.

Common Mistakes

MistakeConsequenceHow to avoid
Omitting amount when intending a partial refundA full refund is performed insteadAlways specify amount for partial refunds
Issuing partial refunds exceeding the order totalThe API rejects the requestTrack cumulative refunded amounts per order
Not checking supplier BA balance before refundingRefund may fail if marketplace funding is disabledEnable marketplace funding policy or ensure supplier BAs are funded

Error Reference

For the complete list of DJUST error and warning codes, refer to the dedicated page:
Error / Warning codes


Related Documentation



Did this page help you?