Managing a fulfillment order
In Digital River coordinated fulfillments, learn how to use the Fulfillment Orders API and Shipments API to manage fulfillment of physical products
A fulfillment order manages the fulfillment of a transaction's SKU-inventory item pairs. You only use this resource in Digital River coordinated fulfillments.
If you're using the distributed model, you must send a create fulfillment order request to initiate physical fulfillment.
If you're using the orchestrated model, Digital River submits this fulfillment order request for you.
In both the distributed and orchestrated models, you should subscribe to events that occur during a fulfillment order's lifecycle. These events notify you of (1) pending shipments, (2) backordered products, (3) shipped products and (4) product cancellations.
In the distributed model, once you either synchronously or asynchronously receive an order in an
accepted
state, your integration should handle the order state change event by sending a create fulfillment order request. This POST/fulfillment-orders
request initiates the fulfillment of a transaction's SKU-inventory item pairs.In the orchestrated model, we listen for an
accepted
order and handle this state change event by internally submitting a create fulfillment order request.The following describes the request's required data and optional data:
Every
POST/fulfillment-orders
request must include currency, created time, shipping address, shipping method, and product data.Order in an accepted state | | POST/fulfillment-orders |
currency | ➔ | currency |
createdTime | ➔ | upstreamOrderTime |
shipTo.country | ➔ | shipTo.country |
shippingChoice.serviceLevel | ➔ | shippingChoice.id |
items[].skuId | ➔ | items[].inventoryItemId |
items[].quantity | ➔ | items[].quantity |
items[].tax.amount | ➔ | items[].tax.amount |
In addition to other optional data, a
POST/fulfillment-orders
request accepts product, customer, ship to, upstream order identifier, and locale data. If you placed a hold on products, you should also attach the reservation identifier.items[].id | ➔ | items[].upstreamId |
items[].amount | ➔ | items[].total |
shipTo.name or billTo.name | ➔ | name or shipTo.name |
shipTo.phone or billTo.phone | ➔ | phone or shipTo.phone |
shipTo.email or billTo.email | ➔ | email or shipTo.email |
shipTo | ➔ | shipTo |
id | ➔ | upstreamId |
locale | ➔ | locale |
checkoutId | ➔ | reservationId |
The
currency
in the request should be the same as the value in the upstream order. This avoids creating downstream invoicing errors, issues with customs, and incorrect tax computations.As with all dates and times in the Digital River APIs, the
createdTime
of the upstream order is in UTC and adheres to the ISO-8601 standard. You should not modify this date-time value before using it to set upstreamOrderTime
in a fulfillment order.{
"id": "186962110336",
"createdTime": "2021-04-02T18:46:45Z",
...
}
You can set the customer's
name
, email
, and phone
at the fulfillment order level and within shipTo
.The fulfillment order's
reservationId
should reference the reservation that was used to place a hold on the products.When creating a reservation, you should set the reservation's identifier value to be same as the checkout's identifier.
If the create fulfillment order request doesn't contain a
reservationId
, Digital River still attempts to allocate the specified inventory items. If we determine inventory levels are too low, what happens at that point depends on whether you allow overselling of an item and whether your channel is set up to accept backorders.When setting the fulfillment order's
shippingChoice.id
, you should use the order's shippingChoice.serviceLevel
. This value maps to the identifier of the shipping quote selected by the customer.Shipping quote | Text | Order | Text | Fulfillment Order |
---|---|---|---|---|
id | ➔ | shippingChoice.serviceLevel | ➔ | shippingChoice.id |
If you want to set the fulfillment order's
signatureRequiredType
, you'll need to persist the shipping quote selected by the customer. You can then retrieve the shipping quote's signatureRequiredType
and use that value to set the fulfillment order's signatureRequiredType
.If the upstream order triggers the landed cost feature, then set the fulfillment order's
dutiesPaid
to true
. This notifies the shipping carrier that the customer has already paid the full landed cost and they should invoice you for any duties paid.Use the fulfillment order's
items
array to specify product information. The line items must be retrieved from the upstream order. The same is true for most of a fulfillment order's optional product data.For example, you can use
giftMessage
to send the downstream fulfiller a message that customers want included with the package. The giftWrap
flag allows you to indicate whether the product should be wrapped.Once you successfully submit a
POST/fulfillment-orders
request, a fulfillment order contains unique identifiers that are needed for downstream processing. Additionally, we return attributes that inform you of a fulfillment order's state and categorize the status of its line items.Once a fulfillment order is created, we assign it a unique identifier. We also assign unique identifiers to each of its line items. You should persist all of these values.
When submitting product cancellation requests and product return requests, you must provide both the fulfillment order identifier and the relevant line item identifiers.
In the distributed model, you can retrieve these identifiers from the
201 Created
response to a POST/fulfillment-orders
request.In the orchestrated model, you can retrieve these identifiers by listening for the
fulfillment_order.pending
event.You should be aware of both the fulfillment order's lifecycle and the fulfillment order's line item's lifecycle. In both, each stage of the lifecycle is represented by a
state
.The
state
attribute at the fulfillment order level indicates where a fulfillment order is in its lifecycle. The values for a successful fulfillment (i.e., the happy path) are pending
> shipped
.(1) When the fulfillment order... | (2) its state transitions to... |
is created but not yet partially or fully shipped | pending |
partially or fully ships | shipped |
is cancelled by the customer, the client or the fulfiller | cancelled |
The line item
state
attribute indicates where a fulfillment order's line item is in its lifecycle. The values for a successfully fulfilled line item (i.e., the happy path) are pending
> shipped
.(1) When the line item... | (2) its state transitions to... |
has not yet partially or fully shipped | pending |
backordered | |
partially or fully ships | shipped |
is cancelled by the customer, the client or the fulfiller | cancelled |
Each element of fulfillment order's
items
array indicates how many items are pending
, backordered
, shipped
, cancelled
, and returned
. In aggregate, these values equal the total quantity
of that line item, which represents the amount originally purchased by the customer.You can determine a fulfillment order's
state
by either calling the API or listening for webhook events.There are two methods in the Fulfillment Orders API that can be used to retrieve fulfillment orders. You can either get a list of fulfillment orders filtered by optional query parameters. Or you can get an individual fulfillment order by including its unique identifier as a path parameter in the request.
We recommend you respond to a fulfillment order's
state
changes by listening for the pending, backordered, shipped, and cancelled events.In all of these events,
data.object
contains the unique identifier of:When Digital River queues a fulfillment order for creation, we create a
fulfillment_order.pending
event. The event's data.object
is a fulfillment order in a pending
state.In the orchestrated model, use this event to retrieve and save the fulfillment order's identifier as well as each of its line item's identifiers.
Upon receiving a backordered notification from your channel's designated fulfiller, Digital River sends you a
fulfillment_order.backordered
event. The event's data.object
contains an array of backordered items
.For each product in the
items
array, we provide an estimated availableTime
(assuming the fulfiller sends us this information). We also specify the original ordered
quantity as well as the quantity of backOrdered
items that triggered the event.The
totalBackordered
is the aggregated backOrdered
quantity from all the backordered events. When processing duplicate backordered events, you can use this value as a checksum, thereby ensuring your system does not exceed the total ordered
amount.You can use the
fulfillment_order.backordered
event as a trigger to send a delayed order notification (typically an email) to the customer. In the email, we recommend that you provide a link that directs customers to their order management page.On this page, you should provide customers the option to fully or partially cancel the order. If they select either option, make sure you respond to this event by submitting a create fulfillment cancellation request.
fulfillment_order.backordered
{
"id": "evt_e381g2ff-7d42-3b05-91d5-e711443r3521",
...
"data": {
"object": {
...
"items": [
{
...
"ordered": 6,
"backordered": 2,
"totalBackordered": 3,
"availableTime": 2020-11-25T20:36:00Z,
...
}
],
...
},
"previousAttributes": {}
},
...
"type": "fulfillment_order.backordered"
}
Once we receive a shipped notification from your channel's designated fulfiller, we send you a
fulfillment_order.shipped
event. The event's data.object
consists of a shipment. You should persist the shipment's identifier (data.object.id
) so that you can use it to track a shipment's progress.In the event's payload,
fulfillmentOrderUpstreamId
represents the order's unique identifier and items[].fulfillmentOrderItemUpstreamId
represents a line item's identifier in an order.fulfillment_order.shipped
{
"id": "evt_d290f1ee-6c54-4b01-90e6-d701748f0851",
...
"data": {
"object": {
"id": "29016544906",
...
"fulfillmentOrderId": "5774321009",
"fulfillmentOrderUpstreamId": "9292981838",
...
"items": [
{
"id": "8760948870",
"fulfillmentOrderItemId": "650398674428",
"fulfillmentOrderItemUpstreamId": "650398674428",
...
"quantity": 1,
...
}
],
...
},
"previousAttributes": {}
},
...
"type": "fulfillment_order.shipped"
}
In the distributed model, every time you receive
fulfillment_order.shipped
, retrieve data from the event and send it in a POST/fulfillments
request. This request instructs Digital River to capture the appropriate amount of an order's payment charges.In the orchestrated model, we listen for the shipped event and respond to it by submitting an internal payment capture request.
In the request, pass the event's shipment identifier and each shipment item's identifier. You're also required to pass the upstream fulfillment order identifier. Additionally, for each shipped
items
, you must send its upstream fulfillment order item identifier and its shipped quantity
.The following table lists the data you must retrieve from each
fulfillment_order.shipped
event and then pass in a POST/fulfillments
.fulfillment_order.shipped event | | POST/fulfillments |
data.object.id |