Issuing refunds
Learn how to use the Refunds API to issue full and partial refunds
The Refunds API allows you to reimburse customers for product costs, shipping expenses, taxes, duties, and regulatory fees.
Once you configure and create a refund, your integration should be set up to handle refund state changes.
To tailor a refund so that customers are only reimbursed for specific, non-product related expenses, you must specify
type
. This is due to the fact that refunds can only be created on order's with charge
captures[]
in a state
of complete
. To be notified of this state
change event, you can subscribe to order.charge.capture.complete
.If you'd like to cancel a charge before it's captured, use the Fulfillments API. For details, refer to Capturing and cancelling payment charges.
Order
{
"id": "219965900336",
...
"items": [
{
"id": "145174060336",
...
"availableToRefundAmount": 27.01,
...
}
],
"payment": {
"charges": [
{
"id": "07f84c7b-6412-4f75-b0fa-562958ad0b76",
...
"captures": [
{
"id": "d9202f29-6ec9-40d7-a6bc-73510b4e030b",
...
"amount": 27.01,
"state": "complete"
}
],
...
}
],
...
"availableToRefundAmount": 27.01
...
}
Prior to submitting a
POST/refunds
, you can make a GET/orders/{id}
to determine whether the amount
you're requesting is less than or equal to what's available.Order
{
"id": "219496900336",
...
"items": [
{
"id": "144659950336",
...
"availableToRefundAmount": 15.0,
...
},
{
"id": "144659940336",
...
"availableToRefundAmount": 27.01,
...
}
],
...
"availableToRefundAmount": 42.01,
...
}
At a high level, Digital River calculates these values by using the following formula:
availableToRefundAmount =
charge(s)
amount
captured
− (
completed refunds
amount +
pending refunds
amount)
If you submit a
POST/refunds
whose amount
is greater than the order's availableToRefundAmount
, or whose items[].amount
is greater than that items[].availableToRefundAmount
, then a 400 Bad Request
is thrown:Error
{
"type": "bad_request",
"errors": [
{
"code": "invalid_parameter",
"parameter": "amountRequested",
"message": "The requested refund amount is greater than the available amount."
}
]
}
At the order-level,
availableToRefundAmount
reflects the unrefunded portion of an order's capturedAmount
. This availableToRefundAmount
may include product prices, along with any expenses related to shipping, duties, fees, and assessed taxes.Order
{
"id": "235507650336",
...
"capturedAmount": 27.01,
...
"availableToRefundAmount": 13.5,
...
}
If you'd like to refund shipping costs associated with an order's individual
items[]
, then you can determine what customers paid by accessing items[].shipping.amount
and items[].shipping.taxAmount
.In the following example, note that each line item's
availableToRefundAmount
excludes its shipping.amount
and shipping.taxAmount
.Order
{
"id": "237455490336",
...
"items": [
{
...
"amount": 10.0,
...
"tax": {
...
"amount": 0.8
},
...
"availableToRefundAmount": 10.8,
...
"shipping": {
"amount": 2.5,
"taxAmount": 0.2
}
},
{
...
"amount": 10.0,
...
"tax": {
...
"amount": 0.8
},
...
"availableToRefundAmount": 10.8,
...
"shipping": {
"amount": 2.5,
"taxAmount": 0.2
}
}
],
...
}
A
POST/refunds
requires currency
. After you submit this request, Digital River doesn't perform a currency conversion. As a result, the value you pass must be the same as the associated order's currency
. If they're different, a 400 Bad Request
is thrown:Error
{
"type": "bad_request",
"errors": [
{
"code": "invalid_parameter",
"parameter": "currency",
"message": "Currency EUR is not supported."
}
]
}
Prior to submitting a
POST/refunds
request, specific preconditions must exist. Once satisfied, you can request a variety of refunds. The following sections provide information on how to reimburse:- Omits
type
- Either (1) sets
percent
to a value in the range of0.01
to100.00
inclusive or (2) setsamount
to a value that's less than or equal to the order'savailableToRefundAmount
Order-level percent refund request
Order-level amount refund request
curl --location --request POST 'https://api.digitalriver.com/refunds' \
...
--data-raw '{
"orderId": "219974470336",
"currency": "USD",
"percent": 100
}'
curl --location --request POST 'https://api.digitalriver.com/refunds' \
...
--data-raw '{
"orderId": "219974470336",
"currency": "USD",
"amount": "27.01"
}'.
If you set
percent
to 100
or amount
to the order's availableToRefundAmount
, then Digital River attempts to reimburse the full availableToRefundAmount
. If you pass any lower
percent
or amount
, then an order's product costs, shipping expenses, duties, and taxes are proportionally refunded.Product refund requests do not reimburse regulatory fees. To do that, you must set
type
to fees
in a separate POST/refunds
​POST/refunds
Refund
Order
curl --location --request POST 'https://api.digitalriver.com/refunds' \
...
--data-raw '{
"orderId": "219975310336",
"currency": "USD",
"percent": 50
}'
{
"id": "re_c19de38c-22cc-46b7-8e7f-2e4681cc2941",
"amount": 13.51,
...
"orderId": "219975310336",
"refundedAmount": 13.51,
"state": "succeeded",
"liveMode": false,
"charges": [
{
"id": "7c99d449-117a-4502-b1ea-b1e1a5343412",
"captured": true,
"refunded": true,
"refunds": [
{
"createdTime": "2022-03-17T21:04:04Z",
"amount": 13.51,
"state": "complete"
}
],
"sourceId": "9dcee2b0-ce84-4374-84fc-6317729b4dd3"
}
]
}
{
"id": "219975310336",
...
"totalAmount": 27.01,
"subtotal": 25.0,
...
"totalTax": 2.01,
...
"totalShipping": 5.0,
...
"payment": {
"charges": [
{
...
"captures": [
{
...
"amount": 27.01,
"state": "complete"
}
],
"refunded": true,
"refunds": [
{
...
"amount": 13.51,
"state": "complete"
}
],
...
}
],
...
"refundedAmount": 13.51,
...
"capturedAmount": 27.01,
...
"availableToRefundAmount": 13.5,
...
}
- Omits
items[].type
- Specifies an
items[].quantity
that is less than or equal to the correspondingitems[].quantity
in the order​ - Either (1) sets
items[].percent
to a value in the range of0.01
to100.00
, inclusive or (2) setsitems[].amount
to a value that's less than or equal to thatitems[].availableToRefundAmount
.
If you configure the request this way, Digital River attempts to refund the specified
quantity
of items[]
by the given percent
or amount
.POST/refunds
Refund
curl --location --request POST 'https://api.digitalriver.com/refunds' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer sk_test_ea6f3e97c3f94b33b58e39d1c013f364' \
--header 'Cookie: incap_ses_1326_1638494=K9W9dx/1/jBJpcH6UeZmEjJ1PGIAAAAAX3ucdBSpIP2TivcLZF6BfQ==; incap_ses_6522_1638494=KObzY36wLi46+CuXdsyCWgXRPGIAAAAAMZkNGsosFQyIXLdAZCcVCQ==; nlbi_1638494_1914372=0JbidDMPHxouUSQviXZ5LAAAAABdyRk6JGyNhyte+5r6KG2E; nlbi_1638494_2412637=aTFZdFXsLCM1uYBtiXZ5LAAAAAB+sX1j1Jq8H0j4gBwzktpi; visid_incap_1638494=S/ubAWkHTB+qbgwhFj7HgMXaSWEAAAAAQUIPAAAAAADUpxCyuVm7HqaQDmEdHhTm; visid_incap_2137235=YibR5HAMTw28J10M4p6Omyb+vWEAAAAAQUIPAAAAAADLOejzH/0oGlmJVXjAkh4Q; visid_incap_2223514=75hpreQFTEeUoJQziq2pkFOccWEAAAAAQUIPAAAAAADefDtHFYydOaHYPCytcnKS' \
--data-raw '{
"orderId": "220821660336",
"currency": "USD",
"items": [
{
"itemId": "146111340336",
"quantity": "2",
"percent": 100
},
{
"itemId": "146111350336",
"quantity": "4",
"percent": 50
}
]
}'
{
"id": "re_ebbf8180-50f2-4ec7-8a58-f490d1e239d1",
"createdTime": "2022-03-24T20:27:16Z",
"currency": "USD",
"items": [
{
"amount": 21.61,
"quantity": 2,
"refundedAmount": 21.61,
"skuId": "2758690d-01a5-4a3b-b0d7-2081793de8b8",
"itemId": "146111340336"
},
{
"amount": 21.61,
"quantity": 4,
"refundedAmount": 21.61,
"skuId": "dd9d7dc4-3ee2-4003-9e23-c67b6fafac87",
"itemId": "146111350336"
}
],
"orderId": "220821660336",
"refundedAmount": 43.22,
"state": "succeeded",
"liveMode": false,
"charges": [
{
"id": "b5a497f7-d650-4279-8a70-942e72e8232c",
"captured": true,
"refunded": true,
"refunds": [
{
"createdTime": "2022-03-24T20:28:41Z",
"amount": 43.22,
"state": "complete"
}
],
"sourceId": "3d94448d-d9b9-4ebf-ae74-c5839a1a9840"
}
]
Along with product costs, line item-level refund requests using this configuration proportionally reimburse that
items[].tax.amount
. They do not, however, refund any shipping, regulatory fee, importer tax, or duty amounts (along with taxes assessed on those amounts) that are associated with that items[]
.If you want to only reimburse specific, non-product related costs, such as shipping, duties, regulatory fees, and taxes, your
POST/refunds
must specify type
at either the order-level or the line item-level.Order-level
Item-level
curl --location --request POST 'https://api.digitalriver.com/refunds' \
...
--data-raw '{
"orderId": "222671410336",
"currency": "USD",
"type": "shipping",
"percent": 75
}'
curl --location --request POST 'https://api.digitalriver.com/refunds' \
...
--data-raw '{
"orderId": "222671410336",
"currency": "USD",
"items": [
{
"type": "shipping",
"itemId": "148089050336",
"quantity": "2",
"percent": 75
}
]
}'
When
type
is shipping
, fees
, or duty
, any taxes assessed on those particular components of the order are also refunded.For details on how to configure a refund request when
type
is tax
or importer_tax
, refer to Refunding taxes.In
POST/refunds
, by setting type
to tax
, you can reimburse just the tax component of an order. You can't, however, partially refund taxes using type
. If you submit a
POST/refunds
that specifies a type
of tax
, then either (1) percent
must be 100
or (2) amount
must be equal to the unrefunded portion of an order's totalTax
. If either of these conditions are not met, then a 400 Bad Request
is returned.Error
{
"type": "bad_request",
"errors": [
{
"code": "invalid_parameter",
"parameter": "percentRequested",
"message": "Only full tax refunds are supported."
}
]
}
When refunding taxes, we recommend you use
percent
instead of amount
. This is because an order's totalTax
doesn't always reflect how much refundable tax exists. Previous refunds may have reduced what's available.In these cases, if you retrieve an order's
totalTax
, and use that value to set amount
in a POST/refunds
, then a 400 Bad Request
is returned.Error
{
"type": "bad_request",
"errors": [
{
"code": "invalid_parameter",
"parameter": "amountRequested",
"message": "The requested refund amount is greater than the available amount."
}
]
}
After you successfully submit a
POST/refunds
with a type
of tax
, Digital River attempts to reclaim the unrefunded portion of an order's totalTax
.POST/refunds
Refund
Order
curl --location --request POST 'https://api.digitalriver.com/refunds' \
...
--data-raw '{
"orderId": "219965900336",
"currency": "USD",
"type": "tax",
"percent": 100
}'
{
"id": "re_9d55374c-da56-43ea-8da7-5a933f34aa1a",
"amount": 2.01,
"createdTime": "2022-03-17T15:30:18Z",
"currency": "USD",
"type": "tax",
"items": [],
"orderId": "219965900336",
"refundedAmount": 2.01,
"state": "succeeded",
"liveMode": false,
"charges": [
{
"id": "07f84c7b-6412-4f75-b0fa-562958ad0b76",
"captured": true,
"refunded": true,
"refunds": [
{
"createdTime": "2022-03-17T15:32:45Z",
"amount": 2.01,
"state": "complete"
}
],
"sourceId": "68868a82-b0d7-41c7-9868-03feb145546d"
}
]
}
{
"id": "219965900336",
...
"totalAmount": 27.01,
"subtotal": 25.0,
...
"totalTax": 2.01,
...
"payment": {
"charges": [
{
"id": "07f84c7b-6412-4f75-b0fa-562958ad0b76",
...
"captures": [
{
"id": "d9202f29-6ec9-40d7-a6bc-73510b4e030b",
...
"amount": 27.01,
"state": "complete"
}
],
"refunded": true,
"refunds": [
{
...
"amount": 2.01,
"state": "complete"
}
],
...
}
],
...
"refundedAmount": 2.01,
...
"capturedAmount": 27.01,
...
"availableToRefundAmount": 25.0,
...
}
You also have the ability to issue refunds only on shipping costs. To do this, set
type
to shipping
and specify an amount
or percent
.We recommend using
percent
instead of amount
. This is because an order's totalShipping
doesn't always reflect the actual refundable shipping costs. Previous refunds may have reduced what's available.In these cases, if you retrieve
totalShipping
, and use that value to set amount
in a POST/refunds
, then a 400 Bad Request
is returned.Depending on the value you assign
percent
, passing a type
of shipping
fully or partially refunds both an order's shippingChoice.amount
and shippingChoice.tax
POST/refunds
Refund
Order
curl --location --request POST 'https://api.digitalriver.com/refunds' \
...
--data-raw '{
"orderId": "220527740336",
"currency": "USD",
"type": "shipping",
"percent": 100
}'
{
"id": "re_7cc420ed-7089-43ba-bb0b-0b5dc95105bd",
"amount": 5.4,
"createdTime": "2022-03-22T20:17:49Z",
"currency": "USD",
"type": "shipping",
"items": [],
"orderId": "220527740336",
"refundedAmount": 5.4,
"state": "succeeded",
"liveMode": false,
"charges": [
{
"id": "1abef982-0ede-4faa-a493-d100e5d2c6c1",
"captured": true,
"refunded": true,
"refunds": [
{
"createdTime": "2022-03-22T20:23:20Z",
"amount": 5.4,
"state": "complete"
}
],
"sourceId": "798b0ff3-81c3-45f4-b779-29b1ac2a3aac"
}
]
}
{
"id": "220527740336",
...
"totalAmount": 27.01,
"subtotal": 25.0,
...
"totalTax": 2.01,
...
"totalShipping": 5.0,
...
"shippingChoice": {
...
"amount": 5.0,
...
"taxAmount": 0.4,
...
},
...
"payment": {
"charges": [
{
...
"refunded": true,
"refunds": [
{
...
"amount": 5.4,
"state": "complete"
}
],
...
}
],
...
"refundedAmount": 5.4,
...
"capturedAmount": 27.01,
...
"availableToRefundAmount": 21.61,
...
}
After submitting a refund request, we recommend that your integration be set up to listen for the following events:
When a
POST/refunds
is successful, Digital River sets the refund's state
to pending
and creates a refund.pending
event.This
state
indicates that Digital River and the payment processor have all the information they need to initiate the refund process.A
201 Created
response code doesn't signify that the bank approved the refund. It only means that your refund request was successfully sent. To be notified of approved refunds, listen for the refund.complete
event.refund.pending (order-level)
refund.pending (item-level)
{
"id": "07b04605-0089-4789-af46-4cefb34786ef",
"type": "refund.pending",
"data": {
"object": {
"id": "re_252eb3f4-81b2-4576-aabd-6af2df248e99",
"amount": 13.51,
"createdTime": "2022-03-17T16:17:54Z",
"currency": "USD",
"items": [],
"orderId": "219966860336",
"refundedAmount": 0.0,
"state": "pending",
"liveMode": false
}
},
"liveMode": false,
"createdTime": "2022-03-17T16:17:54.93644Z",
"webhookIds": [
"bbac1929-580c-4629-b648-4c096b1a104a",
"6d7055fc-b3b6-42fb-97a8-2443386199fb"
],
"digitalriverVersion": "2021-12-13"
}
{
"id": "749267cf-a86e-471e-ab70-e4b315c9b9c4",
"type": "refund.pending",
"data": {
"object": {
"id": "re_e0779bb1-7af2-43f5-9225-35a282d86f66",
"createdTime": "2022-03-21T21:46:54Z",
"currency": "USD",
"items": [
{
"amount": 21.61,
"quantity": 2,
"refundedAmount": 0.0,
"skuId": "4dc8b640-0c74-48f1-bec0-39b947c5dde7",
"itemId": "145634580336"
},
{
"amount": 72.92,
"quantity": 3,
"refundedAmount": 0.0,
"skuId": "4dc8b640-0c74-48f1-bec0-39b947c5dde7",
"itemId": "145634590336"
}
],
"orderId": "220400480336",
"refundedAmount": 0.0,
"state": "pending",
"liveMode": false
}
},
"liveMode": false,
"createdTime": "2022-03-21T21:46:55.215753Z",
"webhookIds": [
"bbac1929-580c-4629-b648-4c096b1a104a",
"6d7055fc-b3b6-42fb-97a8-2443386199fb"
],
"digitalriverVersion": "2021-12-13"
}
You can use
refund.pending
to trigger a notification to customers, informing them that their refund is being processed. Make sure you also update the status of the refund on their order details page.In some cases, customers must first supply their banking details before payment processors act on a refund request. This is common when the purchase was made with a wire transfer or other delayed payment method.
When the bank requests this additional information, Digital River moves the refund's
state
to pending_information
and creates a refund.pending_information
event.For more information on how to handle this
state
change, refer to the Refunding asynchronous payment methods page.To notify customers of successfully processed refunds, you can also configure a webhook to listen for
order.refunded
.In the payload,
amount
is how much you requested be refunded and refundedAmount
is the actual reimbursed amount.refund.complete (order-level)
refund.complete (item-level)
{
"id": "ebd5dcb3-7028-4a78-8efb-3d7ca918e96e",
"type": "refund.complete",
"data": {
"object": {
"id": "re_252eb3f4-81b2-4576-aabd-6af2df248e99",
"amount": 13.51,
"createdTime": "2022-03-17T16:17:54Z",
"currency": "USD",
"items": [],
"orderId": "219966860336",
"refundedAmount": 13.51,
"state": "succeeded",
"liveMode": false,
"charges": [
{
"id": "b46e2189-fd69-4819-a886-f43c89283bda",
"captured": true,
"refunded": true,
"refunds": [
{
"createdTime": "2022-03-17T16:22:14Z",
"amount": 13.51,
"state": "complete"
}
],
"sourceId": "cca536f3-93ed-40e8-bd79-99a3dcf2edf8"
}
]
}
},
"liveMode": false,
"createdTime": "2022-03-17T16:23:29.233283Z",
"webhookIds": [
"bbac1929-580c-4629-b648-4c096b1a104a",
"6d7055fc-b3b6-42fb-97a8-2443386199fb"
],
"digitalriverVersion": "2021-12-13"
}
{
"id": "a1afc456-338a-427f-b888-33cdd11ea1e4",
"type": "refund.complete",
"data": {
"object": {
"id": "re_e0779bb1-7af2-43f5-9225-35a282d86f66",
"createdTime": "2022-03-21T21:46:54Z",
"currency": "USD",
"items": [
{
"amount": 21.61,
"quantity": 2,
"refundedAmount": 21.61,
"skuId": "4dc8b640-0c74-48f1-bec0-39b947c5dde7",
"itemId": "145634580336"
},
{
"amount": 72.92,
"quantity"