Capturing and cancelling charges
Learn how to inform Digital River that products are fulfilled or cancelled so that we can attempt to capture or cancel payment
Once you create an order, and handle the necessary events, you can use the Fulfillments API to notify Digital River of fulfilled and cancelled items. Each time you define and submit a POST/fulfillments request, you're informing our payment services how many items in an order are fulfilled and/or cancelled. We then use that information to capture or cancel the appropriate amount of an order's payment charges.
Once you submit a POST/fulfillments, your integration should also be set up to handle fulfillment-related events.

Receiving the necessary events

Before you submit a POST/fulfillment request, you must first receive and handle the necessary events. The specific events you must process depend on the order's fulfillment model:
Upstream requirement
Digital River coordinated fulfillments (distributed model)
Digital River coordinated fulfillments (orchestrated model)
Third party coordinated fulfillments
An order in an accepted state

Third party coordinated fulfillments

In most integrations, you respond to this order state change by sending a fulfillment request to your logistics partner and when the products are shipped, your partner sends you a shipment notification. You should respond to this notification by defining a POST/fulfillments with the quantity of each shipped line item and then submitting the payment capture request.
Similarly, when an item is successfully cancelled, your fulfiller typically sends you a cancelled shipment notification. Respond to this notification by defining a POST/fulfillments with the cancelQuantity of each cancelled line item and then submitting the payment cancel request.

Digital River coordinated fulfillments

In Digital River coordinated fulfillments, the specific events you must process depends on whether you're using the distributed model or the orchestrated model.

Distributed model

In the distributed model, you need to handle an accepted order by creating a fulfillment order. You must then wait to receive a fulfillment_order.shipped event before handling that by defining a POST/fulfillments with the quantity of each shipped line item and then submitting the payment capture request.
Similarly, in this model, you must also wait to receive a fulfillment_order.cancelled event before handling that by defining a POST/fulfillments with the cancelQuantity of each cancelled line item and then submitting the payment cancel request.

Orchestrated model

In the orchestrated model, you don't need to respond to any of these events. Our orchestration service monitors the key commerce and fulfillment events and then handles the payment capture and cancel process.

Defining fulfillments

You do this by providing an order identifier, information about each fulfilled and/or cancelled item, as well as any shipment identifiers and tracking data provided by your fulfiller.

Fulfilled and cancelled items

In the request's items array, you specify each line item's unique identifier and the quantity fulfilled and/or cancelled. The request doesn't need to specify both a quantity and cancelQuantity, but it must contain one or the other.
If you specify a quantity, thereby informing our payment services that these items are fulfilled, we attempt to capture the appropriate amount of the payment charge. Conversely, if you specify a cancelQuantity, we attempt to cancel the relevant charge amount.

Shipment identifiers

In Digital River coordinated fulfillments that use the distributed model, a POST/fulfillments must include shipment identifiers. Specifically, you're required to provide a single shipmentId and, for each item in the shipment, a unique shipmentItemId.
You obtain these identifiers from the fulfillment_order.shipped event. Each time you receive this shipment notification, retrieve these identifiers and pass them in the POST/fulfillments.

Tracking data

You can also include information on the name of the trackingCompany, the trackingNumber provided by the shipping carrier, and the trackingUrl that customers use to monitor the shipment.
In third-party coordinated fulfillments, you typically receive this tracking information from your fulfiller when they notify you of a shipment.
In Digital River coordinated fulfillments that use the distributed model, you can retrieve this information from the fulfillment_order.shipped event.

Submitting payment capture and cancellation requests

Each time you send a POST/fulfillments and receive a 201 Created, the payload contains a fulfillment with a unique identifier. The request also triggers a fulfillment.created event.
Once you submit one or more POST/fulfillments that result in every line item's state transitioning to fulfilled, then the order's state also becomes fulfilled and an order.fulfilled event is fired.
At this point, if you submit any additional POST/fulfillments on the order, you receive the following 409 Conflict:
409 Conflict
1
{
2
"type": "conflict",
3
"errors": [
4
{
5
"code": "order_fulfilled",
6
"parameter": "orderId",
7
"message": "Resource '201454110336' is fulfilled."
8
}
9
]
10
}
Copied!

Handling fulfillment-related events

Depending on your integration, you might find it useful to subscribe to the fulfillment created event. We recommend however that all integrations handle charge capture and charge cancel events as well as the order complete event.

Fulfillment created event

In Digital River coordinated fulfillments that use the orchestrated model, the fulfillment.created event is useful for accessing tracking data. The event provides the name of the shipping company, a unique tracking number, and a url to track the delivery's progress.
You can also obtain this data from the fulfillment_order.shipped event.
fulfillment.created
1
{
2
"id": "5203007c-c3e9-47f0-a5aa-51e512fbd3ea",
3
"type": "fulfillment.created",
4
"data": {
5
"object": {
6
"id": "ful_c34fd193-94a6-469f-89c2-fd09f50827be",
7
"createdTime": "2021-10-03T02:28:08Z",
8
"items": [
9
{
10
"quantity": 1,
11
"cancelQuantity": 0,
12
"skuId": "4220a17e-730b-437c-b98f-d5c63f47529b",
13
"itemId": "123930940336"
14
}
15
],
16
"orderId": "201073480336",
17
"shipmentId": "100002369153",
18
"trackingCompany": "Fedex",
19
"trackingNumber": "Z10100002632653",
20
"trackingUrl": "http://www.fedex.com/Tracking?tracknumbers=Z10100002632653",
21
"liveMode": false
22
}
23
},
24
"liveMode": false,
25
"createdTime": "2021-10-03T02:28:09.21052Z",
26
"digitalriverVersion": "2021-03-23"
27
}
Copied!
From the event's payload, retrieve orderId, items[].itemId, trackingCompany, trackingNumber, and trackingUrl. You can use orderId and items[].itemId to look up the order and line item(s) in your system and then add the tracking information to the customer's order management page.
You could also use the event to trigger a shipped notification to the customer (typically an email) that contains this tracking information.

Charge capture complete and failed events

Your integration should be set up to handle order.charge.capture.complete and order.charge.capture.failed events. The payload of both consists of a charge and contains a fulfillmentId that identifies the fulfillment which triggered the event.

Successful charge captures

An order.charge.capture.complete event indicates that Digital River fully or partially captured one of an order's charges.
In the following example, the charge's state remains capturable because the order is only partially fulfilled.
order.charge.capture.complete
1
{
2
"id": "f275be0a-45fd-4160-8a31-b3274b6a4f8b",
3
"type": "order.charge.capture.complete",
4
"data": {
5
"object": {
6
"id": "b67136cc-0b2e-43f7-8d9a-362047aa975a",
7
"createdTime": "2022-03-02T16:50:23Z",
8
"currency": "USD",
9
"amount": 37.81,
10
"state": "capturable",
11
"orderId": "218377480336",
12
"captured": true,
13
"captures": [
14
{
15
"id": "b496b7b2-3bc7-49cd-ab48-f91b2f2e37cc",
16
"createdTime": "2022-03-02T16:50:37Z",
17
"amount": 25.21,
18
"state": "complete",
19
"fulfillmentId": "ful_a0246997-bdcf-480a-a066-2cfc564e6232"
20
}
21
],
22
"refunded": false,
23
"sourceId": "52ca4456-5547-4f9c-8016-1a067fd0b125",
24
"paymentSessionId": "7c121712-2ae8-4617-97a2-5d41fd79a5b8",
25
"type": "customer_initiated",
26
"liveMode": false
27
}
28
},
29
"liveMode": false,
30
"createdTime": "2022-03-02T16:52:01.180061Z",
31
...
32
"digitalriverVersion": "2021-12-13"
33
}
Copied!
Upon receiving this event, you can notify customers of the amount captured, the payment method used to make the capture, relevant product details, and any shipment tracking information that may be available.
The event's captures[].amount and captures[].createdTime provides the data you need to inform customers how much and when they were charged.
To access data on the payment source associated with the capture, pass the event's sourceId as a path parameter in a GET/sources/{sourceId}.
In this example, the customer used a credit card, so from the 200 OK response you'd most likely retrieve creditCard.brand and creditCard.lastFourDigits.
Source
1
{
2
"id": "52ca4456-5547-4f9c-8016-1a067fd0b125",
3
"createdTime": "2022-03-02T16:49:48Z",
4
"type": "creditCard",
5
"reusable": false,
6
"state": "consumed",
7
...
8
"clientSecret": "52ca4456-5547-4f9c-8016-1a067fd0b125_ae8fb67f-bcf4-49ac-9a6d-3427ce5d5f20",
9
"creditCard": {
10
"brand": "Visa",
11
"expirationMonth": 7,
12
"expirationYear": 2027,
13
"lastFourDigits": "1111"
14
},
15
"liveMode": false
16
}
Copied!
To access product and tracking data, use the event's captures[].fulfillmentId to retrieve the fulfillment that triggered the capture. From the 200 OK response, fetch each items[].skuId and pass the value in a GET/skus/{skuId}. This allows you to access the SKU's name, description, image, and other product data. Depending on your integration, the fulfillment may also contain shipment tracking data.
Fulfillment
SKU
1
{
2
"id": "ful_a0246997-bdcf-480a-a066-2cfc564e6232",
3
"createdTime": "2022-03-02T16:50:36Z",
4
"items": [
5
{
6
"quantity": 2,
7
"cancelQuantity": 0,
8
"skuId": "066a6672-7358-4aef-9127-41ef16314b9f",
9
"itemId": "143380150336"
10
}
11
],
12
"orderId": "218377480336",
13
"liveMode": false,
14
"chargeOperationIds": [
15
"b496b7b2-3bc7-49cd-ab48-f91b2f2e37cc"
16
]
17
}
Copied!
1
{
2
"id": "066a6672-7358-4aef-9127-41ef16314b9f",
3
...
4
"name": "Test Product",
5
...
6
"image": "https://www.your-site.com/productImage.png",
7
"description": "The description of a test product",
8
...
9
}
Copied!
You can use the the event's orderId to look up the order in your system and provide some or all of this capture, payment, product, and shipping information on the customer's order details page. For example:
We billed your creditCard.brand ending in creditCard.lastFourDigits in the amount of captures[].amount on captures[].createdTime. This payment is for the following products:
  • name | description | image

Failed charge captures

In rare cases, a capture fails. If this happens, Digital River creates an order.charge.capture.failed event.
To handle this event, we recommend that you:
  • Send a shipment cancellation request to your fulfillment logistics partner. The event's captures[].fulfillmentId allows you to retrieve the fulfillment, access its shipmentId and items[].shipmentItemId and then use these identifiers to cancel the shipment. Make sure you check with your fulfiller to determine whether they have the ability to cancel a shipment within a certain window of time. If you're using Digital River's fulfillment service, refer to Cancelling physical fulfillments.
  • Contact the customer to arrange a return or alternate payment.
Failed captures are usually due to expired charge authorizations. This might happen when you're running a pre-order sale and there's a lengthy period between submission of a POST/orders that authorizes the charge and a POST/fulfillments that captures payment.
Failed captures might also be due to fulfillment delays on the part of your logistics partner.
On the Testing scenarios page, we provide credit card information that you can use to check how your integration handles failed charge captures.
order.charge.capture.failed
1
{
2
"id": "61b66e77-cc9a-4144-b048-f0bf06aff777",
3
"type": "order.charge.capture.failed",
4
"data": {
5
"object": {
6
"id": "3b4ef391-e8ae-412a-994b-df3e447aafa0",
7
"createdTime": "2022-03-02T17:38:35Z",
8
"currency": "USD",
9
"amount": 37.81,
10
"state": "capturable",
11
"orderId": "218378950336",
12
"captured": true,
13
"captures": [
14
{
15
"id": "7542f424-7615-4748-8af6-9c04001ce2e8",
16
"createdTime": "2022-03-02T17:38:51Z",
17
"amount": 37.81,
18
"state": "failed",
19
"failureCode": "failed-request",
20
"fulfillmentId": "ful_2bbb92e0-16fa-4a62-952e-4e2ca4df2870"
21
}
22
],
23
"refunded": false,
24
"sourceId": "e13b2327-d94d-4a62-821c-f11693e64ede",
25
"paymentSessionId": "d149962c-80fc-4f7b-b4fc-bc8a80482aef",
26
"type": "customer_initiated",
27
"liveMode": false
28
}
29
},
30
"liveMode": false,
31
"createdTime": "2022-03-02T17:38:54.966905Z",
32
...
33
"digitalriverVersion": "2021-12-13"
34
}
Copied!
The failed capture event contains a failureCode. We also provide a failureMessage that may help diagnose the issue. To access this message:
  1. 1.
    Save the unique id of the event's capture.
  2. 2.
    Retrieve the event's data.object.id, which uniquely identifies the charge.
  3. 3.
    Send this charge identifier as a path parameter in a GET/charges/{id}.
  4. 4.
    In the 200 OK response, use the saved capture identifier to search captures[] for the appropriate element and retrieve its failureMessage.
In nearly all cases, however, failureCode is failed-request and failureMessage is Failed to operate on charge. This indicates that Digital River was unable to determine a reason for the capture failure.

The charge cancel success event

We recommend that your integration be setup to handle successful charge cancellations.
The order.charge.cancel.complete event typically originates with a customer making a request on your site to cancel an entire order (or a certain quantity of one or more line items in an order).
This request, in turn, should eventually trigger a POST/fulfillments that specifies a cancelQuantity for each line item that the customer wants to cancel.
In physical fulfillments, make sure you send a shipment cancellation request to your fulfiller, and receive a successful response, before sending the charge cancellation request to Digital River.
order.charge.cancel.complete
1
{
2
"id": "96640a35-40bc-4e44-8b33-34c623fd3713",
3
"type": "order.charge.cancel.complete",
4
"data": {
5
"object": {
6
"id": "66ebb961-c60e-49d8-9dce-32f6be1e770e",
7
"createdTime": "2021-10-05T09:07:06Z",
8
"currency": "USD",
9
"amount": 54.1,
10
"state": "capturable",
11
"orderId": "201293880336",
12
"captured": false,
13
"refunded": false,
14
"cancels": [
15
{
16
"id": "9c755ce0-b52d-4a77-97d7-c7ed73931156",
17
"createdTime": "2021-10-05T09:07:15Z",
18
"amount": 10.82,
19
"state": "complete"
20
}
21
],
22
"sourceId": "a7e5633f-572c-4a7b-9991-e8ff2f3a2f7a",
23
"paymentSessionId": "beaaa4cb-67fd-43fa-b57d-7b0b447afc60",
24
"type": "customer_initiated",
25
"liveMode": false
26
}
27
},
28
"liveMode": false,
29
"createdTime": "2021-10-05T09:07:17.160189Z",
30
"webhookIds": [
31
"bbac1929-580c-4629-b648-4c096b1a104a",
32
"6d7055fc-b3b6-42fb-97a8-2443386199fb",
33
"8044a862-e7c9-4a8f-a3bb-b6b987a2be9e"
34
],
35
"digitalriverVersion": "2021-03-23"
36
}
Copied!
Upon receipt of the charge cancellation event, inform customers of the cancelled payment.
To do this, retrieve the event's orderId, cancels[].createdTime and cancels[].amount. To access information about the source, retrieve the event's sourceId and pass it as a path parameter in a GET/sources/{sourceId}.
In this example order, the customer used a credit card, so you'd retrieve creditCard.brand and creditCard.lastFourDigits from the response.
Source
1
{
2
"id": "a7e5633f-572c-4a7b-9991-e8ff2f3a2f7a",
3
"createdTime": "2021-10-05T09:06:58Z",
4
"type": "creditCard",
5
"reusable": false,
6
"state": "consumed",
7
"owner": {
8
"firstName": "Guy",
9
"lastName": "Incognito",
10
"email": "[email protected]",
11
"address": {
12
"line1": "1234 St.",
13
"city": "Minnetonka",
14
"postalCode": "55341",
15
"state": "MN",
16
"country": "US"
17
}
18
},
19
"clientSecret": "a7e5633f-572c-4a7b-9991-e8ff2f3a2f7a_caa2ec51-453b-4f29-971d-cb6ffc594e22",
20
"creditCard": {
21
"brand": "Visa",
22
"expirationMonth": 10,
23
"expirationYear": 2022,
24
"lastFourDigits": "1111"
25
},
26
"liveMode": false
27
}
Copied!
You can use the event's orderId to locate the order in your system and display the cancel payment information to customers on their order details page. For example:
On cancels[].createdTime we cancelled billing on your creditCard.brand ending in creditCard.lastFourDigits in the amount of cancels[].amount.

The order complete event

When the order moves into a complete state, an order.complete event is fired. Upon receipt of this event, use the event's data.object.id or data.object.upstreamId to look up the order in your system and set its state to complete.
The order.complete event can also act as a trigger to populate the customer's order details page. The following lists some of the information you may decide to display on this page, along with the field in the event that contains the data. Most likely, you've already used prior API responses and events to store much of this data in your system.
Order details page
Event's data.object field
Order number
id
Date of order
createdTime
Shipping address
shipTo.address
Billing address
billTo.address
Order total
totalAmount
Total before tax
subtotal
Fees
totalFees
Taxes
totalTax
Duties
totalDuty
Shipping and handling
totalShipping
Line items details
items[]
Payment method(s)
payment.sources[].type
Billing date(s)
payment.charges[].captures[].createdTime
Billing amount(s)
payment.charges[].captures[].amount
Billing cancellation date(s)
payment.charges[].cancels[].createdTime
Billing cancellation amount(s)
payment.charges[].cancels[].amount
You can also use order.complete as a trigger to activate a request refund button on the customer's order details page. When handling the button's click event, make sure you use the Refunds API to process the request.