Interacting with Global Logistics in checkouts

If you've selected the Direct Integrations option, gain a better understanding of how to interact with Global Logistics in checkouts

If you implement a Direct Integration checkout solution and enable Global Logistics, this page contains an overview of how to manage the checkout process. You'll also find details on how to:

Overview

During checkouts, Digital River's Global Logistics (GL) service gives you the capability to request international shipping quotes. Digital River routes your request to the appropriate global logistics provider (GLP) and then uses their response to provide you with a menu of shipping options that you can optionally filter and then display to customers.

Once customers select a shipping quote, apply their choice to the checkout, and then, assuming they selected a quote with delivered duty paid (DDP) terms, use the duty, fee, and import tax amounts returned by Digital River to present customers with a transaction's full landed cost.

Building a cart

During the early stages of an ecommerce transaction, customers land on your storefront, review products, build a cart, confirm the cart's details, and initiate checkout. This cart-building process is roughly the same for both domestic and international transactions.

However, some of your products might have country restrictions applied to them. In other words, products which are prohibited from being imported into certain countries.

To handle this, you might want to block customers from adding restricted products to their carts. This helps avoid issues at customs as well as unanticipated return costs.

Plug-ins and extensions exist that geo-locate a customer's country. These add-ons then hide products from customers who are located in restricted countries. Some of these extensions allow you to disable the add-to-cart button for prohibited product-country combinations.

Creating the checkout

However you send product data in create checkout requests, make sure each physical items[] has a name, description, weight, image, url, and itemBreadcrumb. For details, refer to:

For each of these items[], if you want the carrier to provide one or more logisticsOptions, and you decided not to save these options in the product's SKU Group, then make sure you enumerate them in deliveryOptions[] and/or dangerousGoods[]. This ensures that each of these services gets added to the order.

curl --location 'https://api.digitalriver.com/checkouts' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <Secret API key>' \
...
--data-raw '{
    ...
    "items": [
        {
            "productDetails": {
                "id": "Thor-Ankleboot-8-8",
                "skuGroupId": "62b05273-ec28-44ab-9e55-a7a3eef99fdb",
                "name": "Thor's Ankleboot",
                "countryOfOrigin": "US",
                "image": "https://drapi.io/img/prod/shoes_men_ankleboot.png",
                "url": "https://drapi.io/img/prod/shoes_men_ankleboot.png",
                "description": "Shoes for Thor, improved",
                "itemBreadcrumb": "Shoes > Mens > Thor"
            },
            "logisticsOptions": {
                "deliveryOptions": [
                    "direct_delivery_only",
                    "additional_handling"
                ]
            },
            "quantity": 1,
            "price": 500
        }
    ],
    ...
}'

Handling ship to country restrictions

Once you initiate checkout, you should obtain the customer's name, email, shipping address, and billing address.

For details, refer to sequencing the checkout process on the Building checkouts page.

When collecting a customer's shipping information in your checkout experience, we suggest using a drop-down menu (or a similar graphical control element) that restricts available ship to countries to those defined by your trading patterns, plus any additional countries you may be shipping to with the help of another logistics service.

Managing shipping quotes

Once you collect the customer's ship to information, define and send a shipping quotes request to Digital River. The quality of the data you provide in this request determines the accuracy of the returned shipping quotes.

We transform your request and route it to the appropriate global logistics provider (GLP).

Upon receiving a successful shipping quote response, you could handle the response by applying a filter before displaying the quotes to customers. Once the customer makes a selection, handle that event by retrieving data from the selected quote and using it to update the checkout.

Defining and sending the shipping quote request

A POST /shipping-quotes request must pass a currency, ship to address, as well as product and package data.

curl --location 'https://api.digitalriver.com/shipping-quotes' \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer <Secret API Key>' \
....
    "currency": "USD",
    "shipTo": {
        "address": {
            "line1": "Rudi-Dutschke-Straße 26",
            "city": "Berlin",
            "postalCode": "10969",
            "country": "DE"
        },
        "name": "Chase Marshall"
    },
    "packages": [
        {
            "items": [
                {
                    "productDetails": {
                        "id": "Thor-Ankleboot-8-8",
                        "skuGroupId": "62b05273-ec28-44ab-9e55-a7a3eef99fdb",
                        "name": "Thor'\''s Ankleboot",
                        "countryOfOrigin": "US",
                        "image": "https://drapi.io/img/prod/shoes_men_ankleboot.png",
                        "description": "Shoes for Thor, improved"
                    },
                    "logisticsOptions": {
                        "deliveryOptions": [
                            "direct_delivery_only",
                            "additional_handling"
                        ]
                    },
                    "amount": 500,
                    "quantity": 1
                }
            ],
            "weight": 10,
            "weightUnit": "oz",
            "height": 5,
            "width": 5,
            "length": 5
        }
    ]
}'

Currency

The cost of each returned shipping quote is converted into this currency. It should be the same value as the checkout's currency.

Ship to

To make the shipping quotes as accurate as possible, map the checkout's shipTo to the request's shipTo.

Ship from

Assign the address of the product's warehouse to shipFrom. It's not a requirement because Global Logistics identifies the appropriate trading pattern by using the request's shipTo.address.country.

Packaging and product data

Your request must contain data on the packages[] being shipped and the items[] within each. In multi-package transactions, this allows you to designate which products will be sent in each parcel, potentially making the returned shipping rates more precise.

If you have a dynamic packing integration with your WMS, you could call that service prior to making a POST/ shipping-quotes and provide it data on the physical products in the customer's cart so that its algorithms can tell you the optimal number of packages[], the weight, height, width, and length of each, plus which items[] should go in those packages[] and then pass that data to Digital River in the request.

For details on why it's important that the quote request that Digital River routes to the designated GLP contains weight values, refer to Product weight and dunnage.

Additionally, you might have large products which you know are always packaged individually. In this case, for each of these product types, you can send one packages[] with a single items[] with a quantity of 1.

For each packages[]:

  • height, width, and length must be greater than 0 and should be defined in inches. If you don't have default package dimensions saved to your account, then they're all required.

  • The weight should be an approximation of the product and packaging weight. It must be greater than 0.If you don't have a default package weight saved to your account and no weight values exist in the items[].productDetails of this packages[], then it's required.

    • For each items[] in that packages[]:

      • Map its productDetails to those in the checkout. Defining weight is optional unless you have no default package weight saved to your account and packages[].weight isn't defined.

      • Map itslogisticsOptions to any that exist in the checkout. This ensures that the appropriate fees are added to the shipping quotes that customers select from. However, if you decided to save these options in the product's SKU Group, then this is not a requirement.

      • quantity is required because it's a key input for accurately calculating shipping rates.

How your request gets processed

Digital River retrieves product and packaging data from your shipping quotes request and uses it to define another request that we route to the appropriate GLP. We also determine whether any products in the request are classified as dangerous goods and/or require a signature, and, if this is the case, pass that data to the GLP.

When the GLP responds to our request with a list of quotes, we convert the cost of each back into the same currency you specified in your request. For each quote returned by the GLP, we also aggregate any carrier-assessed fees and surcharges into a single total amount.

Successful shipping quotes response

A successful POST /shipping-quotes request returns a currency and an array of shipping quotes[].

200
{
    "currency": "USD",
    "quotes": [
        {
            "id": "54",
            "description": "UPS® Worldwide Express Plus",
            "serviceLevel": "UPS Worldwide Express Plus",
            "deliveryInformation": {
                "businessDaysInTransit": "2 Business Days",
                "estimatedArrival": {
                    "date": "2024-03-27T09:00:00",
                    "dayOfWeek": "Wednesday"
                },
                "pickupDate": "2024-03-25T18:30:00",
                "weekendService": {
                    "saturdayDelivery": false
                },
                "supportCutoffTime": "17:30:00"
            },
            "shippingTerms": "DDP",
            "totalAmount": 139.89,
            "shipFrom": {
                "address": {
                    "line1": "55, York St",
                    "city": "Toronto",
                    "postalCode": "M5J 1R9",
                    "state": "ON",
                    "country": "CA"
                }
            },
            "fees": {
                "details": [
                    {
                        "name": "375",
                        "amount": 23.31
                    },
                    {
                        "name": "430-Commercial_Seasonal_Surcharge",
                        "amount": 0.05
                    }
                ],
                "amount": 23.36
            }
        },
        {
            "id": "07",
            "description": "UPS® Worldwide Express",
            "serviceLevel": "UPS Worldwide Express",
            "deliveryInformation": {
                "businessDaysInTransit": "2 Business Days",
                "estimatedArrival": {
                    "date": "2024-03-27T10:30:00",
                    "dayOfWeek": "Wednesday"
                },
                "pickupDate": "2024-03-25T18:30:00",
                "weekendService": {
                    "saturdayDelivery": false
                },
                "supportCutoffTime": "17:30:00"
            },
            "shippingTerms": "DDP",
            "totalAmount": 76.1,
            "shipFrom": {
                "address": {
                    "line1": "55, York St",
                    "city": "Toronto",
                    "postalCode": "M5J 1R9",
                    "state": "ON",
                    "country": "CA"
                }
            },
            "fees": {
                "details": [
                    {
                        "name": "375",
                        "amount": 12.68
                    },
                    {
                        "name": "430-Commercial_Seasonal_Surcharge",
                        "amount": 0.05
                    }
                ],
                "amount": 12.73
            }
        },
        {
            "id": "65",
            "description": "UPS Express® Saver",
            "serviceLevel": "UPS Express Saver",
            "deliveryInformation": {
                "businessDaysInTransit": "2 Business Days",
                "estimatedArrival": {
                    "date": "2024-03-27T23:30:00",
                    "dayOfWeek": "Wednesday"
                },
                "pickupDate": "2024-03-25T18:30:00",
                "weekendService": {
                    "saturdayDelivery": false
                },
                "supportCutoffTime": "17:30:00"
            },
            "shippingTerms": "DDP",
            "totalAmount": 72.35,
            "shipFrom": {
                "address": {
                    "line1": "55, York St",
                    "city": "Toronto",
                    "postalCode": "M5J 1R9",
                    "state": "ON",
                    "country": "CA"
                }
            },
            "fees": {
                "details": [
                    {
                        "name": "375",
                        "amount": 12.06
                    },
                    {
                        "name": "430-Commercial_Seasonal_Surcharge",
                        "amount": 0.05
                    }
                ],
                "amount": 12.11
            }
        },
        {
            "id": "08",
            "description": "UPS® Worldwide Expedited",
            "serviceLevel": "UPS Worldwide Expedited",
            "deliveryInformation": {
                "businessDaysInTransit": "6 Business Days",
                "estimatedArrival": {
                    "date": "2024-04-03T23:30:00",
                    "dayOfWeek": "Wednesday"
                },
                "pickupDate": "2024-03-25T18:30:00",
                "weekendService": {
                    "saturdayDelivery": false
                },
                "supportCutoffTime": "17:30:00"
            },
            "shippingTerms": "DDP",
            "totalAmount": 67.79,
            "shipFrom": {
                "address": {
                    "line1": "55, York St",
                    "city": "Toronto",
                    "postalCode": "M5J 1R9",
                    "state": "ON",
                    "country": "CA"
                }
            },
            "fees": {
                "details": [
                    {
                        "name": "375",
                        "amount": 11.3
                    },
                    {
                        "name": "430-Commercial_Seasonal_Surcharge",
                        "amount": 0.05
                    }
                ],
                "amount": 11.35
            }
        }
    ],
    "liveMode": false
}

The currency is always the same value that you sent in the request.

Each element in quotes[] contains the following attributes:

Unique identifier

Each quotes[] has a unique id, which is generated by the GLP.

This id doesn't reference a resource, so you can't use it to make an API call to retrieve a unique shipping quote.

When handling a customer's shipping quote selection, use the selected quote's id to define the checkout's shippingChoice.id. If you don't perform this operation, then the downstream create shipping label request will fail.

Description

The description indicates the duration of transportation. In other words, how quickly the goods are transported to the customer and what priority level they are assigned. Some common values are Economy, Express, and Priority. This is a pass-thru value from the GLP.

Delivery information

Each quotes[] contains deliveryInformation about that particular shipping option.

Which nested objects exist within deliveryInformationdepends on the GLP that is facilitating the transaction. For example, not all GLPs provide an estimatedArrival.

The businessDaysInTransit is the estimated number of business days that the shipment will be in transit before it arrives at its final destination. Its value might be a single day or a range of days.

The estimatedArrival provides the date and dayOfWeek when the shipment is expected to arrive. It's conditional on both pickupDate and supportCutoffTime. If the carrier collects the shipment by supportCutoffTime on pickupDate, then it should be at its destination by estimatedArrival.date. For example, if the customer selects the following quote and the final mile carrier picks up the shipment by 6:30 pm on 3-25-24, then it should arrive at its final destination on Wednesday, 3-27-24.

{
    "currency": "USD",
    "quotes": [
        {
            "id": "54",
            ...
            "deliveryInformation": {
                "businessDaysInTransit": "2 Business Days",
                "estimatedArrival": {
                    "date": "2024-03-27T09:00:00",
                    "dayOfWeek": "Wednesday"
                },
                "pickupDate": "2024-03-25T18:30:00",
                "weekendService": {
                    "saturdayDelivery": false
                },
                "supportCutoffTime": "17:30:00"
            },
            ...
        },
        ...
    ],
    "liveMode": false
}

You can use weekendService to determine whether the shipment has additional fees for a saturdayDelivery or sundayDelivery. If either boolean is true, then delivery will be scheduled for that day and an additional charge for the service is added to fees.details[]. If false, then (1) delivery on that day is not available or (2) it is available but no additional fees are collected. In the second case, check dayOfWeek to determine if it's a weekend delivery.

Shipping terms

A quote's shippingTerms are designated as either DDP or DAP. These values indicate when customers must pay duties, fees, and import taxes.

In delivered-duty-paid (DDP) shipments, customers pays all duties, fees, and import taxes upfront during the checkout process. Upon product delivery, there are no additional charges they must pay.

In delivered-at-place (DAP) shipments, customers do not pay the full landed cost at checkout-time. Instead, they pay product and shipping costs, and then, upon delivery, they're responsible for paying duties, fees, and import taxes.

Shipping costs and fees

The totalAmount of a quotes[] represents how much customers must pay to ship the goods to their final destination. It includes the estimated cost of handling, transportation, and postage as well as carrier-assessed surcharges and fees.

In fees, we itemize these estimated fees and surcharges. A carrier might collect them to, for example, offset the cost of higher fuel prices, package signature options, or dangerous goods handling requirements.

Each quote's totalAmount, fees.amount, and fees.details[].amount is denominated in the response's single currency.

Ship from

Each shipping quote's shipFrom represents the address where that product is warehoused.

If you maintain multiple warehouses in the same country, then the response might contain one or more quotes[] with the same shipFrom.address.country but other attributes nested in shipFrom.address (such as line1 and city) that contain non-matching values.

Failure response

Besides not meeting the requirements listed in the POST /shipping-quotes specifications, your request might also fail due to (1) an invalid trading pattern, (2) invalid or missing package dimensions, or (3) an invalid or missing package weight.

Invalid trading pattern

If shipFrom.address.country and shipTo.address.country are not supported by your trading patterns, then an error with a 400 status code is returned.

{
    "type": "bad_request",
    "errors": [
        {
            "code": "invalid_parameter",
            "parameter": "shipTo.address",
            "message": "The shipTo.address is invalid with the shipFrom.address"
        }
    ]
}

Invalid or missing package dimensions

If a packages[] doesn’t have a height, width, and length that is greater than 0, and no default dimensional values are saved to your account, then an error with a 409 status code is returned:

{
    "type": "conflict",
    "errors": [
        {
            "code": "invalid_parameter",
            "message": "The package dimensions are missing or invalid."
        }
    ]
}

Invalid or missing package weight

If (1) a packages[] doesn’t have a weight that is greater than 0, and (2) none of the items[].productDetails in that packages[] has a weight that is greater than 0, and (3) no default package weight is saved to your account, then an error with a 400 status code is returned:

{
    "type": "bad_request",
    "errors": [
        {
            "code": "invalid_parameter",
            "message": "The package weight is required."
        }
    ]
}

Handling the shipping quotes response

Depending on your business objectives, you may decide you want to filter and adjust the returned shipping quotes before displaying them to customers.

Filtering and adjusting shipping quotes

If you want to avoid fees incurred by weekend deliveries, then discard any quotes[] whose saturdayDelivery or sundayDelivery value is true.

By only displaying quotes[] whose shippingTerms are DDP, you can help minimize rejections, returns, and chargebacks. Shipments with DAP terms generally have higher return rates. At the time of delivery, some customers may be unaware of the outstanding balance and, in response, either refuse the delivery altogether or accept the delivery and then return the products. However, you should be aware that some carriers and ship to country combinations don't support the prepay DDP option. In these cases, the only quotes[] in a successful response are those with shippingTerms of DAP. So, if one of your ship to countries doesn't support DDP, make sure you have logic in place that displays DAP quotes in the event DDP quotes are not returned.

If you'd like to offer your customers a discount on shipping costs, you can reduce one or more quotes[].totalAmount values before displaying them to customers. Just make sure you pass this reduced amount when setting the checkout's shippingChoice.

Displaying shipping quotes

For each shipping quote that you display to customers in your checkout UI, reveal its serviceLeveland totalAmount.

You can also check which attributes exist in deliveryInformation, and then display the available information, such as date and dayOfWeek in estimatedArrival or businessDaysInTransit that you'd like to present to customers.

If you'd like to provide customers with more shipping cost granularity, you can also display fees.details[] and/or fees.amount.

In addition, you should indicate whether the quote's shippingTerms are DAP or DDP. However, we recommend not displaying these acronyms in your UI. Few, if any, customers will understand their meaning. Instead, display a more user-friendly description. For example:

Shipping termCustomer-facing text

DAP

Import charges collected upon delivery

DDP

No additional import charges at delivery

Here's an example of what this might look like:

Handling the shipping quote selection

When customers select a shipping quote, handle that event by retrieving the following data from their selection and using it to define shippingChoice and shipFrom in an update checkout request:

If you don't map the quote's id to the checkout's shippingChoice.id, then the downstream shipping label request will fail.

Shipping quotePOST /checkouts/{id}

id

shippingChoice.id

amount

shippingChoice.amount

description

shippingChoice.description

serviceLevel

shippingChoice.serviceLevel

shippingTerms

shippingChoice.shippingTerms

shipFrom

shipFrom

If all the necessary preconditions are met, this request prompts Digital River to call its landed cost service.

If the checkout's shippingTerms are DDP, then the response to your request provides recalculated duty, fee, and import tax amounts at both the checkout level and items[] level.

For details, refer to how landed cost is represented in checkouts on the Landed cost page.

In the Global Logistics solution, the customer is the designated importer of record. As a result, the customer pays the checkout's totalImporterTax.

If the checkout's shippingTerms are DAP, then checkout-level and items[] level duty, fee, and import tax amounts are all zero.

{
    "id": "206bfba3-7bda-4d0b-b6e3-657875b5cc6c",
    "createdTime": "2021-11-11T22:25:24Z",
    "currency": "EUR",
    "email": "jsmith@digitalriver.com",
    "shipTo": {
        "address": {
            "line1": "Neuer Wall 10",
            "city": "Hamburg",
            "postalCode": "20354",
            "country": "DE"
        },
        "name": "John",
        "phone": "9526123456",
        "email": "john@digitalriver.com"
    },
    "shipFrom": {
        "address": {
            "line1": "Landed Cost Cross Order",
            "line2": "80 Sunraysia Road",
            "city": "INVERMAY",
            "postalCode": "3352",
            "state": "Victoria",
            "country": "AU"
        }
    },
    "totalAmount": 1809.99,
    "subtotal": 1809.99,
    "totalFees": 0.0,
    "totalTax": 0.0,
    "totalImporterTax": 288.99,
    "importerOfRecordTax": true,
    "totalDuty": 221.0,
    "totalDiscount": 0.0,
    "totalShipping": 100.0,
    "items": [
        {
            "id": "434e3932-a20d-49d3-ad82-0abb25eaa9be",
            "skuId": "3c99757b-a543-455f-bbd3-57dc1bb21579",
            "amount": 1200.0,
            "quantity": 3,
            "tax": {
                "rate": 0.36,
                "amount": 0.0
            },
            "importerTax": {
                "amount": 288.99
            },
            "duties": {
                "amount": 221.0
            },
            "fees": {
                "amount": 0.0,
                "taxAmount": 0.0
            },
            "tariffCode": "6404201000"
        }
    ],
    "shippingChoice": {
        "id": "testDDP",
        "amount": 100.0,
        "description": "FedEx Next Day",
        "serviceLevel": "Test",
        "taxAmount": 0.0,
        "shippingTerms": "DDP"
    },
    "updatedTime": "2021-11-11T22:25:24Z",
    "locale": "en_US",
    "customerType": "individual",
    "sellingEntity": {
        "id": "DR_IRELAND-ENTITY",
        "name": "Digital River Ireland Ltd."
    },
    "liveMode": false,
    "payment": {
        "session": {
            "id": "1822d8bd-1531-40da-aedc-10ac9b0eda4c",
            "amountContributed": 0.0,
            "amountRemainingToBeContributed": 1809.99,
            "state": "requires_source",
            "clientSecret": "1822d8bd-1531-40da-aedc-10ac9b0eda4c_4b58e8ed-505c-4334-b349-bc65be9029e5"
        }
    }
}

In both DAP and DDP scenarios, use the checkout data to update the product, shipping, duties, fees, taxes, and total amounts displayed to customers. When displaying duty and import tax amounts in DAP scenarios, let customers know they don't pay these costs at checkout time. We recommend using language such as "Outstanding" or "Collected upon delivery".

Here's an example of what this might look like:

Collecting payment

In Global Logistics, you collect payment in the same way you would in any checkout flow.

Before initiating the payment collection process, you obtain the customer's billing information and use it to set (at a minimum) the checkout's billTo.address.country.

Once you initiate payment collection, Drop-in payments only display payment methods applicable to that currency and bill to country.

If you're using DigitalRiver.js with elements to collect payment, make sure that only applicable payment methods are presented to customers by calling retrieveAvailablePaymentMethods().

For details, refer to:

Submitting the order

Once the necessary preconditions are met, you can convert the checkout to an order. After the order's state either synchronously or asynchronously moves to accepted, send a ship request to your third-party logistics (3PL) provider.

For details, refer to Managing a Global Logistics order.

Last updated