Shipping Method API
Shipping methods in EverShop are produced by shipping providers. A provider is registered at bootstrap (the built-in one has the code core) and attached to one or more shipping zones. When a cart has a shipping address, every provider attached to a matching zone is asked for its methods, and the merged list is what the customer picks from.
That split drives the API surface:
- Listing available methods is a GraphQL query on the cart — the list depends on the cart's contents and destination, so it cannot be a static REST collection.
- Selecting a method is the single REST endpoint documented below.
GET /api/shippingMethods and GET /api/carts/{cart_id}/shippingMethods no longer exist. Read the available methods with the GraphQL query below, and the currently selected one with Cart.shippingMethodData.
List Available Shipping Methods (GraphQL)
Query Cart.availableShippingMethods against the storefront endpoint POST /graphql. The destination arguments are optional — when omitted the cart's saved shipping address is used.
query AvailableShippingMethods($cartId: String!) {
cart(id: $cartId) {
availableShippingMethods(country: "US", province: "CA", postcode: "90001") {
id
providerCode
code
name
cost {
value
text
}
carrier
serviceCode
delivery {
minBusinessDays
maxBusinessDays
estimatedDate
}
}
}
}
Both providerCode and code are required when the customer commits to a method — keep them together as you carry the selection through your UI.
| Field | Type | Description |
|---|---|---|
| id | String! | Alias of code, kept for backward compatibility |
| providerCode | String! | Code of the provider that produced this method. Send it back as provider_code when selecting |
| code | String! | Provider-opaque method identifier. Send it back as method_code |
| name | String! | Customer-facing method name |
| cost | Price! | Quoted cost in the cart's currency |
| carrier | String | Customer-facing carrier label (e.g. USPS). Usually null for Core-only stores |
| serviceCode | String | Fulfillment metadata used when buying a label. Never display it |
| delivery | DeliveryWindow | Estimated delivery window when the provider supplies one |
method_code is opaqueDo not hardcode values like "standard" or "express". The code is whatever the provider chooses to emit — the built-in Core provider returns the core_shipping_method.uuid of the admin-defined method. Always read the code from availableShippingMethods and echo it back verbatim.
Set Shipping Method for Cart
Applies a selected shipping method to a shopping cart. The server re-quotes the method against the cart's current state and stores an enriched snapshot in cart.shipping_method_data.
| Field Name | Field Type | Required |
|---|---|---|
| provider_code | string | Yes |
| method_code | string | Yes |
- cURL
- JavaScript
curl
-H "Accept: application/json"
--data-raw "<JSON DATA>"
https://<your domain>/api/carts/{cart_id}/shippingMethods
fetch('https://<your domain>/api/carts/{cart_id}/shippingMethods', {
headers: {
'Accept': 'application/json',
},
body: <JSON DATA>
})
.then(response => response.json())
.then(data => {
if(data.error) {
// Handle the error
} else {
// Handle the data
}
})
.catch(error => {
// Handle the error
});
{
"data": {
"method": {
"code": "0f1c8b7a-9d3e-4f2a-a1b6-77d4c2e9b510",
"provider_code": "core"
}
}
}
provider_code is mandatoryEarlier releases defaulted the provider to core when the field was absent. That default is gone: a payload without provider_code is rejected with 400 provider_code is required. Silently defaulting routed non-core selections through Core's validator and surfaced later as a misleading "method no longer available" error.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| cart_id | string | Yes | The UUID of the cart to apply the shipping method to |
Reading Back the Selection
The cart.shipping_method and cart.shipping_method_name columns were dropped, along with their order counterparts. The selection now lives in the shipping_method_data JSONB column, exposed as Cart.shippingMethodData:
query SelectedShippingMethod($cartId: String!) {
cart(id: $cartId) {
shippingMethodData {
providerCode
methodCode
snapshot {
code
name
cost {
value
text
}
carrier
}
fingerprint
quotedAt
}
}
}
The underlying column looks like this:
{
"provider_code": "core",
"method_code": "0f1c8b7a-9d3e-4f2a-a1b6-77d4c2e9b510",
"snapshot": {
"code": "0f1c8b7a-9d3e-4f2a-a1b6-77d4c2e9b510",
"name": "Standard Shipping",
"cost": 5.99,
"carrier": "usps",
"serviceCode": "usps_ground_advantage"
},
"fingerprint": "3d0f9a...",
"quotedAt": "2025-04-04T09:12:44.201Z"
}
fingerprint and quotedAt are cart-only. When the cart's items, address, or totals change, the snapshot is re-quoted against the provider automatically — a method that no longer applies raises the shipping-quote error described below.
Managing Providers, Methods and Rates
Creating the methods that customers see is an admin task and lives on different endpoints:
| Endpoint | Purpose |
|---|---|
POST /api/shippingZones/:zone_id/providers | Attach a provider to a zone |
PATCH /api/shippingZones/:zone_id/providers/:provider_code | Enable/disable or reconfigure an attachment |
DELETE /api/shippingZones/:zone_id/providers/:provider_code | Detach a provider from a zone |
POST /api/shippingProviders/core/methods | Create a Core shipping method |
POST /api/shippingProviders/core/rates | Give a Core method a per-zone rate |
See the Shipping Zone API for the full schemas.
Troubleshooting
Shipping Quote Errors
When the selection cannot be quoted, the endpoint answers 400 with a provider-specific reason in error.message. These are user-facing strings — surface them at checkout rather than a generic failure.
| Message | Cause |
|---|---|
| provider_code is required | The payload omitted provider_code |
| Missing provider_code or method_code | One of the two fields was present but empty |
| Shipping provider "x" is not registered | No provider with that code is registered at bootstrap |
| Shipping address is required | The cart has no shipping address, so no zone can be resolved |
| We do not ship to this address | No shipping zone matches the cart's destination |
| Invalid cart | No cart exists with the supplied cart_id |
Common Error Codes
| Status Code | Description | Solution |
|---|---|---|
| 400 | Bad Request | A missing field, an unknown cart, or a shipping-quote rejection. Read error.message |
| 401 | Unauthorized | Only relevant on the admin provider/method endpoints — check your access token |
| 429 | Too Many Requests | The /api/** tier allows 120 requests per minute per IP. Back off using the Retry-After header |
| 500 | Server Error | Unexpected failure while saving the cart. Check the server logs |