Processing orders
Learn the basics of processing an order
Once customers are done checking out, how an order is created depends on whether you integrate with Prebuilt Checkout or Direct Integrations.
If you're using Direct Integrations, first convert the checkout to an order and then handle the immediate response.
If you're using Prebuilt Checkout, then Digital River handles order creation. You do, however, need to listen for and respond to the
checkout_session.order.created
event.With both integration paths, make sure you're set up to handle key events that occur early in an order's lifecycle.
With Direct Integrations, once the checkout's address and payment requirements are met and customers have reviewed and submitted their order, you should pass
checkoutId
in the body of a POST/orders
.POST/orders
curl --location --request POST 'https://api.digitalriver.com/orders' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_key>' \
--data-raw '{
"checkoutId": "177452470336"
}'
This request primarily serves to authorize payment. Once submitted, your integration should be set up to process the immediate response as well as respond to key events.
You can submit a
POST/orders
whose payload contains checkoutId
plus additional parameters (provided they adhere to the request's data contract). But, when processing the request, Digital River ignores this additional data. So, if you'd like to update the checkout, you must do so prior to submitting a POST/orders
.Checkout
If you submit a
POST/orders
that contains the checkout's identifier, an updated email
, and also adds an upstreamId
that identifies the order in your system, then the response contains a 201 Created
status code. However, email
is not updated and upstreamId
is not populated.POST/orders
Order
curl --location --request POST 'https://api.digitalriver.com/orders' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_key>' \
...
--data-raw '{
"checkoutId": "856adaff-0176-4bdb-91cb-7304dfd1e7a9",
"email": "[email protected]",
"upstreamId": "1J9F17710A6"
}'
{
"id": "189917880336",
...
"email": "[email protected]",
...
"checkoutId": "856adaff-0176-4bdb-91cb-7304dfd1e7a9"
}
Although not the preferred approach, you can omit
checkoutId
in a POST/orders
and, instead, create an order with a registered customer's identifier.If you're using Direct Integrations, after you submit the
POST /orders
(assuming all upstream checkout requirements have been met), the response will contain a 409 Conflict
or 201 Created
status code.When handling this immediate response, you need to capture specific data from its payload and use it to update the status of your commerce system. This ensures that downstream fulfillment operations are correctly handled.
A
409 Conflict
status code indicates that Digital River did not create an order, either due to a payment authorization failure or suspected fraud. The error's code
and message
contain more specific information about what triggered the failure.Error
{
"type": "conflict",
"errors": [
{
"code": "failed-request",
"message": "Failed to charge source."
}
]
}
Use this error information to update the upstream order's overall status, payment status, and fraud status.
You can also use the error's
message
to inform end customers of the problem. Do not, however, share code
. Doing so may aid parties that are attempting to carry out fraudulent or malicious activities.For more details on how to process responses with a
409 Conflict
status code, refer to the Handling rejected orders page.From the response's payload, retrieve the order's
id
, state
, fraudState
, and charges[].state
, and use these values to update the corresponding attributes in the upstream commerce platform's order.If an order's
state
is pending_payment
, then the fraud review process has been successfully completed but the payment charge is not yet authorized. For more details, refer to handling pending payment orders.If an order's
state
is in_review
, then this indicates that Digital River is conducting a secondary fraud review. For more information, refer to handling in review orders.If an order's
state
is accepted
, then the transaction has successfully passed fraud review and the payment charge is authorized. For more information, refer to handling accepted orders.With both Prebuilt Checkout and Direct Integrations, your integration should subscribe to some key events that occur early in an order's lifecycle.
These events notify you of:
Each time you're notified of one of these events, retrieve the order's
state
, fraudState
, and charges[].state
(if available) from its payload, and use this data to update the corresponding attributes in the upstream commerce system's order.If you receive this event, you can iterate over the order's
payment.charges[]
and inspect them for a failure code or message. The failureMessage
however is not always available. But when it is, you can use it to provide more specific payment failure information to customers.Do not display the
failureCode
to end customers. Doing so potentially aids malicious and fraudulent actors.When Digital River detects an anomaly during its fraud review, or we determine that the customer is on the Denied Persons List, we create an
order.blocked
event. The payload of this event consists of an order whose state
is blocked
. The order's fraudState
is also blocked
. Since these are both terminal states, you should inform end customers that the transaction has failed.An
order.pending_payment
event indicates that Digital River detected no fraudulent activity during its fraud review. However, don't use this event as a trigger to initiate fulfillment operations. This is because the order's payment.charges[]
are not yet fully authorized.When all of an order's
payment.charges[]
are authorized and no irregularities are detected during the fraud review, Digital River creates an order.accepted
event. Respond to this event by moving the commerce platform's order into a ready to fulfill state.Unless you synchronously receive an order in an
accepted
state, your integration should wait until it receives order.accepted
before initiating fulfillment operations. Doing so reduces the risk of fraud and the frequency of disputes and chargebacks.Since the event is not currently configured to provide a reason for the cancellation,
cancelReason
is not populated.Depending on how you build your integration, the
order.cancelled
event may have multiple origins. For example, if your site contains a cancel order button, then order.cancelled
may originate with customers requesting to cancel their order.If you're using Digital River's fulfillment service, this button’s click event handler should trigger a
POST/fulfillment-cancellations
that requests to fully cancel each of a fulfillment order's line items.If your integration allows customers to submit line-item level cancellation requests (as opposed to the more standard full order cancellations), you can’t always use
order.cancelled
as the event that triggers a cancellation complete notification to customers. This is because, once an order is accepted
, it doesn't become cancelled
until the state
of all of its payment.charges[]
is also cancelled
.The
order.cancelled
event could also be triggered when customers fail to transfer payment by a designated date and time and, as a result, the source expires. This applies to wire transfers, Konibini payments, and other type
(s) of sources with a payment flow
of receiver
.For example, in checkouts whose primary source
type
is wireTransfer
, once you successfully convert the checkout to an order, the order typically moves into a state
of pending_payment
. When handling this order state change event, you should provide instructions to customers on how to provide payment.If customers don't push the funds within the allotted time, then the source expires, no charge authorization is created and the
order.cancelled
event is fired. In this scenario, since no charge is created, you won’t receive any order charge related events.Upon receiving the
order.cancelled
event, we recommend that you:- Update the master order record in your system
- Notify customers (typically by email) that their order has been successfully cancelled and no payment was collected. In the email, we suggest you provide:
- The order number
- The order cancellation date (you can retrieve this information from the order's
stateTransitions.cancelled
attribute) - An itemization of the cancelled goods
- The payment method used by the customer
- The total amount cancelled
- The customer’s billing address
- Your contact information
The following provides information on how to handle pending payment, in review, and accepted orders.
An order that is
pending_payment
indicates that the charge is not yet authorized. Orders in this state
should not be fulfilled.Instead, from the payload of the
POST/orders
response or the order.pending_payment
event, retrieve the payment.sources[].id
of the order's primary payment source.order.pending_payment
{
"id": "65beb271-e660-444d-8919-69c991d63d6d",
"type": "order.pending_payment",
"data": {
"object": {
"id": "196623140336",
...
"payment": {
"sources": [
{
"id": "f853f415-7f85-4695-bd93-7f479efdc4a8",
"type": "wireTransfer",
"amount": 11.33,
...
"wireTransfer": {
"accountHolder": "Global Collect BV",
"bankName": "Rabobank N.A.",
"city": "Ontario",
"country": "US",
"referenceId": "890701505439",
"accountNumber": "0487369908",
"swiftCode": "RABOUS66XXX"
}
}
],
"session": {
"id": "affcead4-92b4-425d-b995-3ebb3fc046f8",
"amountContributed": 11.33,
"amountRemainingToBeContributed": 0.0,
"state": "pending_funds",
"clientSecret": "affcead4-92b4-425d-b995-3ebb3fc046f8_1773afaa-5bb3-4668-b466-b5a49b63653b"
}
},
"state": "pending_payment",
...
"checkoutId": "ab3b00eb-5f32-4c84-8ef3-dc659016d502"
}
},
...
"digitalriverVersion": "2021-03-23"
}
Pass this value as a path parameter in a
GET /sources/{id}
request. From the 200 OK
response, retrieve the source's clientSecret
.Source
{
"id": "f853f415-7f85-4695-bd93-7f479efdc4a8",
"createdTime": "2021-08-23T02:24:02Z",
"type": "wireTransfer",
...
"clientSecret": "f853f415-7f85-4695-bd93-7f479efdc4a8_abec5143-4f72-486c-b377-34d31ddb3c13",
"wireTransfer": {
"accountHolder": "Global Collect BV",
"bankName": "Rabobank N.A.",
"city": "Ontario",
"country": "US",
"referenceId": "74243814931",
"accountNumber": "5215726630",
"swiftCode": "RABOUS29XXX"
},
"liveMode": false
}
Then use both the source's
id
and clientSecret
to configure the front-end create delayed payment instructions element method.let options = {
"sourceId": "f853f415-7f85-4695-bd93-7f479efdc4a8",
"sourceClientSecret": "f853f415-7f85-4695-bd93-7f479efdc4a8_abec5143-4f72-486c-b377-34d31ddb3c13"
}
let delayedPaymentInstructions = digitalRiver.createElement('delayedpaymentinstructions', options);
<div id="delayed-payment-container"></div>
...
delayedPaymentInstructions.mount("delayed-payment-container");
You can optionally configure the element to listen for the ready event. This event signifies that the delayed payment instructions are loaded in the specified container.
delayedPaymentInstructions.on('ready', function(event) {
//delayed payment instructions element is ready
});
The delayed payment instructions are then displayed in the designated container.
These instructions usually inform customers of the number of days that they have to push payment.
<div id="delayed-payment-container">
<div id="delayedpaymentinstructions-c4906e5d-bcc4-482d-aa23-24775f73f035" class="DR-delayed-payment-instructions-container">
<p>Thank you for your order. Please pay at a local branch of the store that you selected.<br><br>The payment will be processed by Digital River, K.K. on our behalf.<br><br>Your order will not be available or shipped until payment has been received and processed.</p>
<p id="DR-konbiniAmountAndReferenceId">
<strong>Amount:</strong> 30.00 USD
<br>
<strong>Reference Number:</strong> 100001
<br>
<strong>Store:</strong> セブン‐イレブン
<br>
</p><p>Please verify your order, and complete payment within 7 days after your order date. <br><br>As soon as the payment is received and confirmed, the product will be made available or shipped. <br><br></p>
<p></p>
</div></div>
If customers follow the instructions and payment is authorized, Digital River creates the
order.accepted
event. If they don't make payment within the allotted time, we create order.cancelled
.Orders that are
in_review
should not be fulfilled. After an order transitions out of this state
, Digital River creates either order.accepted
or order.blocked
. So make sure your integration is set up to handle both of these events.Depending on whether the order is synchronously or asynchronously accepted, you should also redirect customers to an order confirmation page and/or send them a notification (typically an email) that their order has been accepted.
The Purchase Notifications article (refer to Learning tools for access information) contains details on what's required in this notification.
If you attempt to pass a
checkoutId
in a POST/orders
request, and that Checkout has already been consumed by a different POST/orders
request, you'll get back a response with a 404 Not Found
status:JSON
{
"type": "not_found",
"errors": [
{
"code": "not_found",
"parameter": "orderId",
"message": "Order 180139250336 not found"
}
]
}
You do, however, have the ability to submit a
POST/orders
that omits checkoutId
, thereby bypassing the Checkouts API. In this case, the request should contain a registered customer and a reusable payment source saved to that customer's account. The POST/orders
must also meet all currency, address, shipping method, product, and payment session requirements.POST/orders
curl --location --request POST 'https://api.digitalriver.com/orders' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <API_key>' \
...
--data-raw '{
"customerId": "534313260336",
"currency": "USD",
"taxInclusive": false,
"email": "[email protected]",
"shipTo": {
"address": {
"line1": "10380 Bren Road W",
"city": "Minnetonka",
"postalCode": "55343",
"state": "MN",
"country": "US"
},
"name": "John Doe"
},
"shipFrom": {
"address": {
"country": "US"
}
},
"shippingChoice": {
"amount": 5,
"description": "standard",
"serviceLevel": "SG"
},
"items": [
{
"skuId": "aa4dbf0c-2336-4b9c-8cff-5d12664b8266",
"quantity": 2,
"price": 10
}
]
}'