Shipping
Get shipping rates and create shipments
The Shipping module quotes rates, purchases labels, and tracks order fulfillment. Arky selects the backend shipping route and returns carrier, service, rate, tracking, and label details.
Get Shipping Rates
/v1/stores/{storeId}/orders/{orderId}/shipping/rates sdk.eshop.shipment.getRates() Get available shipping rates for selected quantities in an order. Send the persisted fulfillment location, selected order-product quantities, and package facts. Arky loads the origin from the location, loads the destination from the order, and validates both saved addresses before contacting the provider. International quotes also require a complete customs declaration.
import { formatMinor } from "arky-sdk/utils";
const rates = await sdk.eshop.shipment.getRates({
order_id: "ord_abc123",
location_id: "loc_warehouse",
lines: [
{ order_product_id: "order_product_1", quantity: 2 },
{ order_product_id: "order_product_2", quantity: 1 },
],
parcel: {
length: 10,
width: 8,
height: 4,
weight: 2,
distance_unit: "in",
mass_unit: "lb",
},
});
rates.forEach((rate) => {
console.log(
`${rate.carrier} ${rate.service}: ${formatMinor(rate.amount, rate.currency)} (${rate.estimated_days} days)`,
);
});
Parameters
| Name | Type | Description |
|---|---|---|
order_id required | string | Order ID to get rates for |
location_id required | string | Persisted fulfillment location whose address is the origin |
lines required | ShippingRateLine[] | Selected OrderProduct IDs and positive quantities |
parcel required | Parcel | Package dimensions and weight |
customs_declaration optional | CustomsDeclaration | Customs info for international shipments |
ShippingRateLine Object
Parameters
| Name | Type | Description |
|---|---|---|
order_product_id required | string | OrderProduct included in this package |
quantity required | number | Positive quantity included in this package |
Parcel Object
Parameters
| Name | Type | Description |
|---|---|---|
length required | number | Package length |
width required | number | Package width |
height required | number | Package height |
weight required | number | Package weight |
distance_unit required | string | Distance unit (cm, in, ft, mm, m, yd) |
mass_unit required | string | Weight unit (oz, lb, g, kg) |
Rate Response
[
{
"id": "rate_abc",
"carrier": "usps",
"service": "priority",
"display_name": "USPS Priority Mail",
"amount": 895,
"currency": "USD",
"estimated_days": 3
}
]
The returned id is an opaque, expiring signed quote. It binds the order and
location revisions, selected item quantities, and provider rate details. Use
it with the same location and lines when creating the shipment. If the order
or location changes, request rates again.
Create Shipment
/v1/stores/{storeId}/orders/{orderId}/shipments sdk.eshop.shipment.create() Purchase a shipping label and create a shipment for an order. Generate one shipment ID for the
intended shipment and reuse it with the exact same request if the call is interrupted. The response
contains both shipment_id and the complete shipment resource.
import {
clearDurableRequest,
getOrCreateDurableRequest,
withDurableRequestLock,
} from "arky-sdk/utils";
const request = {
order_id: "ord_abc123",
rate_id: "rate_abc",
location_id: "loc_warehouse",
fulfillment_order_id: "fo_abc123",
lines: [
{
order_product_id: "order_product_1",
fulfillment_order_line_id: "fol_1",
quantity: 2,
},
{
order_product_id: "order_product_2",
fulfillment_order_line_id: "fol_2",
quantity: 1,
},
],
};
const storageKey = "arky:shipping-label:store_abc123:ord_abc123";
const result = await withDurableRequestLock(
storageKey,
"shipping-label purchase",
async () => {
const durable = getOrCreateDurableRequest(
storageKey,
request,
"shipping-label purchase",
);
const response = await sdk.eshop.shipment.create({
...request,
shipment_id: durable.id,
});
if (
response.shipment_id !== durable.id ||
response.shipment.id !== durable.id
) {
throw new Error(
"Shipping response did not confirm the requested shipment",
);
}
clearDurableRequest(durable, "shipping-label purchase");
return response;
},
);
console.log(
result.shipment.tracking_number,
result.shipment.shippo_label?.label_url,
);
Parameters
| Name | Type | Description |
|---|---|---|
order_id required | string | Order ID |
shipment_id required | UUID string | Stable caller-owned ID for this shipment resource |
rate_id required | string | Rate ID from getRates response |
location_id required | string | Fulfillment location ID |
fulfillment_order_id optional | string | Fulfillment order being shipped. Recommended for new orders. |
lines required | ShipmentLine[] | Items being shipped |
Do not generate a new shipment ID in an automatic retry. Arky durably records
the label purchase before contacting Shippo and never automatically
repeats a purchase that may have reached the provider. Retrieve the shipment
with sdk.eshop.shipment.get() and inspect shippo_label.status. A failed
purchase can be retried explicitly with sdk.eshop.shipment.retry() only when
its evidence proves the provider call did not start. unknown is terminal and
can never be retried.
Shipment status is one of pending, label_created, in_transit,
out_for_delivery, delivered, failed, returned, or cancelled.
The one Shippo label purchase and its one label-refund workflow are embedded
on shippo_label; shipment money movements remain separate settlement records.
ShipmentLine Object
Parameters
| Name | Type | Description |
|---|---|---|
order_product_id required | string | OrderProduct ID |
fulfillment_order_line_id required | string | Fulfillment order line being satisfied |
quantity required | number | Quantity being shipped |
Customs Declaration (International)
For international shipments, include a customs declaration when fetching rates:
const rates = await sdk.eshop.shipment.getRates({
// ... other params
customs_declaration: {
contents_type: "MERCHANDISE",
contents_explanation: "Clothing items",
non_delivery_option: "RETURN",
certify: true,
certify_signer: "John Doe",
items: [
{
description: "T-Shirt",
quantity: 2,
net_weight: "0.5",
mass_unit: "lb",
value_amount: "25.00",
value_currency: "usd",
origin_country: "US",
},
],
},
});
For US-origin exports, set eel_pfc only from the shipment’s actual filing basis and include
aes_itn when using AES_ITN. Optional incoterm support depends on the selected carrier;
omit these fields unless they apply.
The rate request never accepts address overrides. Correct the order destination or fulfillment-location address, then request rates again if validation fails.
Refund Shippo Label
/v1/stores/{storeId}/orders/{orderId}/shipments/{shipmentId}/shippo-label/refund sdk.eshop.shipment.refund.request() Request the single managed refund for a purchased Shippo label. The refund is an embedded child of that label because there can be at most one. Repeating the request returns the same durable child; it does not create another Shippo refund.
const refund = await sdk.eshop.shipment.refund.request({
order_id: "ord_abc123",
shipment_id: "shipment_abc123",
});
console.log(refund.id, refund.status, refund.safe_error);
Parameters
| Name | Type | Description |
|---|---|---|
order_id required | string | Order ID |
shipment_id required | string | Shipment whose managed label should be refunded |
The refund status is requested, processing, succeeded, rejected, failed, or unknown.
Read it through shipment.shippo_label.refund. A failed refund can be retried explicitly with
sdk.eshop.shipment.refund.retry() only when its evidence proves the Shippo call did not start;
unknown is terminal and can never be retried.
Shipment Settlements
Every platform debit or compensating credit for a shipment is a separate OrderShipmentSettlement
because a shipment can cause multiple money movements with independent lifecycles. List them with
sdk.eshop.shipment.settlement.find(), fetch one with .get(), and explicitly retry a safely
retryable failure with .retry(). Settlement types are purchase_debit,
purchase_compensation_credit, and refund_credit; direction is debit or credit.