API ReferenceEndpointsShipping

Shipping

Shipping zones group regions (countries/states) into pricing buckets, and rates define what each zone costs to ship to. The checkout flow uses these to compute shipping options for each order.

List shipping destinations

Lists the countries and regions the store ships to, from its active shipping zones. Gated on products:read, so it can be used before a cart exists.

GET
/vc/{connectionId}/shipping/destinations
X-Sales-Channel-Origin<token>

For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.

In: header

Path Parameters

connectionIdstring

Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.

Header Parameters

originstring

Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.

X-SDK-Version?string

Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.

curl -X GET "https://api.brainerce.com/api/vc/string/shipping/destinations" \  -H "origin: string" \  -H "X-SDK-Version: string"
{
  "worldwide": false,
  "countries": [
    {
      "code": "US",
      "name": "United States"
    }
  ],
  "regions": {}
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/vc/{connectionId}/shipping/destinations"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/vc/{connectionId}/shipping/destinations"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/vc/{connectionId}/shipping/destinations"
}

List shipping zones with pagination

Lists shipping zones, ordered by priority, 20 per page.

GET
/v1/shipping/zones
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Query Parameters

page?integer

1-based page number.

Default1
Range1 <= value
limit?integer

Items per page. Default 20.

Default20
Range1 <= value
search?string

Case-insensitive match on the zone name.

isActive?boolean

true returns only active zones. Any other value returns only inactive zones. Omit for both.

curl -X GET "https://api.brainerce.com/api/v1/shipping/zones?page=1&limit=20&search=string&isActive=true"
{
  "data": [
    {
      "id": "clx1a2b3c4d5e6f7g8h9",
      "accountId": "clx1a2b3c4d5e6f7g8h9",
      "storeId": "clx1a2b3c4d5e6f7g8h9",
      "name": "US Domestic",
      "countries": [
        "string"
      ],
      "regions": {},
      "postalCodes": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [
              0,
              0
            ]
          ]
        ]
      },
      "hasGeometry": true,
      "geometryLabels": [
        "string"
      ],
      "regionIds": [
        "string"
      ],
      "salesChannelIds": [
        "string"
      ],
      "priority": 1,
      "isActive": true,
      "rateSource": "manual",
      "platformSettings": {},
      "createdAt": "2019-08-24T14:15:22Z",
      "updatedAt": "2019-08-24T14:15:22Z",
      "rates": [
        {
          "id": "clx1a2b3c4d5e6f7g8h9",
          "zoneId": "clx1a2b3c4d5e6f7g8h9",
          "name": "Standard Shipping",
          "description": "Delivery in 3 to 5 business days",
          "type": "FLAT_RATE",
          "rateConfig": {
            "amount": 9.99
          },
          "minDeliveryDays": 3,
          "maxDeliveryDays": 5,
          "handlingTime": 1,
          "requiresPickupPoint": true,
          "taxStatus": "TAXABLE",
          "minOrderAmount": "200.00",
          "maxCost": "50.00",
          "classCosts": {},
          "classCalculationType": "per_class",
          "isActive": true,
          "platformSettings": {},
          "createdAt": "2019-08-24T14:15:22Z",
          "updatedAt": "2019-08-24T14:15:22Z"
        }
      ],
      "_count": {
        "rates": 3
      },
      "ratesCount": 3
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 137,
    "totalPages": 7
  }
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Create a new shipping zone

Supports Idempotency-Key header for safe retries.

POST
/v1/shipping/zones
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
namestring

Display name (shown in the dashboard, never to shoppers).

countriesarray<string>

ISO 3166-1 alpha-2 country codes covered by this zone.

regions?object

Per-country region (state/province) restriction. Keyed by ISO country code; value is an array of subdivision codes. Addresses outside the listed regions do not match the zone.

postalCodes?object

Per-country postal-code patterns, keyed by ISO country code. A pattern is matched exactly and case-sensitively against the customer postal code (no space or hyphen normalisation), or ends in * as a prefix wildcard (941* matches every code starting with 941). Ranges such as 94100-94199 are not supported and match nothing. Only checked once the customer has entered a postal code, and only for countries that have an entry. Further narrows the zone after regions.

geometry?object

Polygon zone definition, a hand-drawn shape ("draw on map"). GeoJSON Polygon or MultiPolygon, ring coordinates in [lng, lat] order (RFC 7946). Independent of countries/regions/postalCodes: a zone matches if the address satisfies either the country-list coverage or the polygon coverage, so both may be set on the same zone.

GeoJSON Polygon. coordinates is an array of rings, each an array of [lng, lat] positions.

typestring
Value in"Polygon"
coordinatesarray<array<array<number>>>

Linear rings. The first ring is the outer boundary and every ring is closed.

GeoJSON MultiPolygon. coordinates is an array of Polygon coordinate arrays.

typestring
Value in"MultiPolygon"
coordinatesarray<array<array<array<number>>>>

One entry per polygon, each an array of linear rings of [lng, lat] positions.

geometryLabels?array<string>

Display-only label per shape in geometry (index 0 = the Polygon, or a MultiPolygon's Nth part), e.g. the searched place name ("Tel Aviv") instead of a generic "Custom area N". Purely cosmetic; never used for matching.

regionIds?array<string>

Region restriction (PRD §25). Region IDs this zone is limited to. Empty/omitted = available for any region (default). Non-empty = the zone is only offered to checkouts whose region is in the list.

salesChannelIds?array<string>

Sales-channel restriction. SalesChannel.id values (the public vc_* connectionId also accepted). Empty/omitted = available on every channel (default). Non-empty = the zone is only offered to checkouts from a channel in the list.

priority?integer

Match priority: a lower value is evaluated first. Defaults to 0.

Default0
Range0 <= value
isActive?boolean

Whether this zone participates in rate calculation. Defaults to true.

Defaulttrue
curl -X POST "https://api.brainerce.com/api/v1/shipping/zones" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{    "name": "United States",    "countries": [      "US",      "CA",      "MX"    ]  }'
{
  "id": "clx1a2b3c4d5e6f7g8h9",
  "accountId": "clx1a2b3c4d5e6f7g8h9",
  "storeId": "clx1a2b3c4d5e6f7g8h9",
  "name": "US Domestic",
  "countries": [
    "string"
  ],
  "regions": {},
  "postalCodes": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [
          0,
          0
        ]
      ]
    ]
  },
  "hasGeometry": true,
  "geometryLabels": [
    "string"
  ],
  "regionIds": [
    "string"
  ],
  "salesChannelIds": [
    "string"
  ],
  "priority": 1,
  "isActive": true,
  "rateSource": "manual",
  "platformSettings": {},
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z",
  "rates": [
    {
      "id": "clx1a2b3c4d5e6f7g8h9",
      "zoneId": "clx1a2b3c4d5e6f7g8h9",
      "name": "Standard Shipping",
      "description": "Delivery in 3 to 5 business days",
      "type": "FLAT_RATE",
      "rateConfig": {
        "amount": 9.99
      },
      "minDeliveryDays": 3,
      "maxDeliveryDays": 5,
      "handlingTime": 1,
      "requiresPickupPoint": true,
      "taxStatus": "TAXABLE",
      "minOrderAmount": "200.00",
      "maxCost": "50.00",
      "classCosts": {},
      "classCalculationType": "per_class",
      "isActive": true,
      "platformSettings": {},
      "createdAt": "2019-08-24T14:15:22Z",
      "updatedAt": "2019-08-24T14:15:22Z"
    }
  ]
}

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Get a single shipping zone by ID

Returns one shipping zone of this store with its countries and rates.

GET
/v1/shipping/zones/{zoneId}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

zoneIdstring

Shipping Zone ID

curl -X GET "https://api.brainerce.com/api/v1/shipping/zones/string"
{
  "id": "clx1a2b3c4d5e6f7g8h9",
  "accountId": "clx1a2b3c4d5e6f7g8h9",
  "storeId": "clx1a2b3c4d5e6f7g8h9",
  "name": "US Domestic",
  "countries": [
    "string"
  ],
  "regions": {},
  "postalCodes": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [
          0,
          0
        ]
      ]
    ]
  },
  "hasGeometry": true,
  "geometryLabels": [
    "string"
  ],
  "regionIds": [
    "string"
  ],
  "salesChannelIds": [
    "string"
  ],
  "priority": 1,
  "isActive": true,
  "rateSource": "manual",
  "platformSettings": {},
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z",
  "rates": [
    {
      "id": "clx1a2b3c4d5e6f7g8h9",
      "zoneId": "clx1a2b3c4d5e6f7g8h9",
      "name": "Standard Shipping",
      "description": "Delivery in 3 to 5 business days",
      "type": "FLAT_RATE",
      "rateConfig": {
        "amount": 9.99
      },
      "minDeliveryDays": 3,
      "maxDeliveryDays": 5,
      "handlingTime": 1,
      "requiresPickupPoint": true,
      "taxStatus": "TAXABLE",
      "minOrderAmount": "200.00",
      "maxCost": "50.00",
      "classCosts": {},
      "classCalculationType": "per_class",
      "isActive": true,
      "platformSettings": {},
      "createdAt": "2019-08-24T14:15:22Z",
      "updatedAt": "2019-08-24T14:15:22Z"
    }
  ]
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Update a shipping zone

Supports Idempotency-Key header for safe retries.

PATCH
/v1/shipping/zones/{zoneId}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

zoneIdstring

Shipping Zone ID

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
name?string

Display name.

countries?array<string>

ISO 3166-1 alpha-2 country codes covered by this zone.

regions?object

Per-country region restriction (subdivision codes).

postalCodes?object

Per-country postal-code patterns, keyed by ISO country code. A pattern is matched exactly and case-sensitively against the customer postal code (no space or hyphen normalisation), or ends in * as a prefix wildcard (941* matches every code starting with 941). Ranges such as 94100-94199 are not supported and match nothing. Only checked once the customer has entered a postal code, and only for countries that have an entry.

geometry?object

Polygon zone definition ("draw on map"). GeoJSON Polygon or MultiPolygon, [lng, lat] ring coordinates. Pass null to clear a previously-set polygon. Omit to leave unchanged.

GeoJSON Polygon. coordinates is an array of rings, each an array of [lng, lat] positions.

typestring
Value in"Polygon"
coordinatesarray<array<array<number>>>

Linear rings. The first ring is the outer boundary and every ring is closed.

GeoJSON MultiPolygon. coordinates is an array of Polygon coordinate arrays.

typestring
Value in"MultiPolygon"
coordinatesarray<array<array<array<number>>>>

One entry per polygon, each an array of linear rings of [lng, lat] positions.

geometryLabels?array<string>

Display-only label per shape in geometry (index 0 = the Polygon, or a MultiPolygon's Nth part). Purely cosmetic; never used for matching. Omit to leave unchanged.

regionIds?array<string>

Region restriction (PRD §25). Region IDs this zone is limited to. Empty array = available for any region. Omit to leave unchanged.

salesChannelIds?array<string>

Sales-channel restriction. SalesChannel.id values (the public vc_* connectionId also accepted). Empty array = available on every channel. Omit to leave unchanged.

priority?integer

Match priority: a lower value is evaluated first.

Range0 <= value
isActive?boolean

Whether this zone participates in rate calculation.

platformSettings?object

Legacy per-platform overrides, keyed by platform code. Stored as-is; nothing reads them to push a zone to another platform.

curl -X PATCH "https://api.brainerce.com/api/v1/shipping/zones/string" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{}'
{
  "id": "clx1a2b3c4d5e6f7g8h9",
  "accountId": "clx1a2b3c4d5e6f7g8h9",
  "storeId": "clx1a2b3c4d5e6f7g8h9",
  "name": "US Domestic",
  "countries": [
    "string"
  ],
  "regions": {},
  "postalCodes": {},
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [
          0,
          0
        ]
      ]
    ]
  },
  "hasGeometry": true,
  "geometryLabels": [
    "string"
  ],
  "regionIds": [
    "string"
  ],
  "salesChannelIds": [
    "string"
  ],
  "priority": 1,
  "isActive": true,
  "rateSource": "manual",
  "platformSettings": {},
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z",
  "rates": [
    {
      "id": "clx1a2b3c4d5e6f7g8h9",
      "zoneId": "clx1a2b3c4d5e6f7g8h9",
      "name": "Standard Shipping",
      "description": "Delivery in 3 to 5 business days",
      "type": "FLAT_RATE",
      "rateConfig": {
        "amount": 9.99
      },
      "minDeliveryDays": 3,
      "maxDeliveryDays": 5,
      "handlingTime": 1,
      "requiresPickupPoint": true,
      "taxStatus": "TAXABLE",
      "minOrderAmount": "200.00",
      "maxCost": "50.00",
      "classCosts": {},
      "classCalculationType": "per_class",
      "isActive": true,
      "platformSettings": {},
      "createdAt": "2019-08-24T14:15:22Z",
      "updatedAt": "2019-08-24T14:15:22Z"
    }
  ]
}

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Delete a shipping zone

Supports Idempotency-Key header for safe retries.

DELETE
/v1/shipping/zones/{zoneId}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

zoneIdstring

Shipping Zone ID

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
curl -X DELETE "https://api.brainerce.com/api/v1/shipping/zones/string" \  -H "Idempotency-Key: string"
Empty

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Get shipping rates for a zone

Returns the rates of one shipping zone.

GET
/v1/shipping/zones/{zoneId}/rates
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

zoneIdstring

Shipping Zone ID

curl -X GET "https://api.brainerce.com/api/v1/shipping/zones/string/rates"
[
  {
    "id": "clx1a2b3c4d5e6f7g8h9",
    "zoneId": "clx1a2b3c4d5e6f7g8h9",
    "name": "Standard Shipping",
    "description": "Delivery in 3 to 5 business days",
    "type": "FLAT_RATE",
    "rateConfig": {
      "amount": 9.99
    },
    "minDeliveryDays": 3,
    "maxDeliveryDays": 5,
    "handlingTime": 1,
    "requiresPickupPoint": true,
    "taxStatus": "TAXABLE",
    "minOrderAmount": "200.00",
    "maxCost": "50.00",
    "classCosts": {},
    "classCalculationType": "per_class",
    "isActive": true,
    "platformSettings": {},
    "createdAt": "2019-08-24T14:15:22Z",
    "updatedAt": "2019-08-24T14:15:22Z"
  }
]

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Create a shipping rate for a zone

Supports Idempotency-Key header for safe retries.

POST
/v1/shipping/zones/{zoneId}/rates
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

zoneIdstring

Shipping Zone ID

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
namestring

Display name shown to shoppers at checkout (e.g. "Standard", "Express").

description?string

Optional short description shown alongside the rate at checkout.

typestring

Rate calculation strategy.

Value in"FLAT_RATE" | "WEIGHT_BASED" | "PRICE_BASED" | "FREE" | "LOCAL_PICKUP"
rateConfigobject

Type-specific configuration. Shape depends on type; see the DTO docs. For FLAT_RATE use { amount: number }.

For type: FLAT_RATE.

amountnumber

Flat shipping cost.

For type: WEIGHT_BASED.

baseRatenumber

Base cost charged on every order.

perKgnumber

Additional cost per kilogram.

maxWeight?number

Maximum order weight in kg this rate serves.

For type: PRICE_BASED.

tiersarray<object>

Cost tiers keyed by the order amount they start at.

For type: FREE.

minOrderAmount?number

Minimum order amount for free shipping. Omit for always free.

For type: LOCAL_PICKUP.

amountnumber

Pickup fee. Use 0 for free pickup.

pickupLocationobject
minDeliveryDays?integer

Minimum delivery time in business days (inclusive).

Range0 <= value
maxDeliveryDays?integer

Maximum delivery time in business days (inclusive).

Range0 <= value
handlingTime?integer

Internal handling time in business days before the package ships.

Range1 <= value
requiresPickupPoint?boolean

Set true on a rate that delivers to a carrier pickup point (a partner shop or locker): the shopper must choose a point before paying. It is offered only to storefronts that can show the choice, and only while an installed shipping app lists points for the destination.

taxStatus?string

Whether the delivery charge itself is taxed. TAXABLE (the default when omitted) taxes it at the Standard rate; NONE leaves postage untaxed.

Default"TAXABLE"
Value in"TAXABLE" | "NONE"
minOrderAmount?number

Minimum cart subtotal required for this rate to be offered. Use to hide low-value carts from free shipping.

Range0 <= value
maxCost?number

Optional cap on the computed cost. Useful for WEIGHT_BASED rates to prevent runaway charges.

Range0 <= value
isActive?boolean

Whether this rate is offered. Defaults to true.

Defaulttrue
classCosts?object

Per-shipping-class cost overrides. Keyed by ShippingClass.id; value is either a flat amount or { first, additional } for first-item + each-additional pricing.

classCalculationType?string

How classCosts are aggregated when the cart mixes classes. per_class charges once per distinct class; per_order once for the whole order; per_item per line-item.

Value in"per_class" | "per_order" | "per_item"
curl -X POST "https://api.brainerce.com/api/v1/shipping/zones/string/rates" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{    "name": "Standard Shipping",    "type": "FLAT_RATE",    "rateConfig": {      "amount": 9.99    }  }'
{
  "id": "clx1a2b3c4d5e6f7g8h9",
  "zoneId": "clx1a2b3c4d5e6f7g8h9",
  "name": "Standard Shipping",
  "description": "Delivery in 3 to 5 business days",
  "type": "FLAT_RATE",
  "rateConfig": {
    "amount": 9.99
  },
  "minDeliveryDays": 3,
  "maxDeliveryDays": 5,
  "handlingTime": 1,
  "requiresPickupPoint": true,
  "taxStatus": "TAXABLE",
  "minOrderAmount": "200.00",
  "maxCost": "50.00",
  "classCosts": {},
  "classCalculationType": "per_class",
  "isActive": true,
  "platformSettings": {},
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z"
}

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Update a shipping rate

Supports Idempotency-Key header for safe retries.

PATCH
/v1/shipping/zones/{zoneId}/rates/{rateId}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

zoneIdstring

Shipping Zone ID

rateIdstring

Shipping Rate ID

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
name?string

Display name shown to shoppers.

description?string

Short description shown alongside the rate.

type?string

Rate calculation strategy.

Value in"FLAT_RATE" | "WEIGHT_BASED" | "PRICE_BASED" | "FREE" | "LOCAL_PICKUP"
rateConfig?object

Type-specific configuration; shape depends on type.

For type: FLAT_RATE.

amountnumber

Flat shipping cost.

For type: WEIGHT_BASED.

baseRatenumber

Base cost charged on every order.

perKgnumber

Additional cost per kilogram.

maxWeight?number

Maximum order weight in kg this rate serves.

For type: PRICE_BASED.

tiersarray<object>

Cost tiers keyed by the order amount they start at.

For type: FREE.

minOrderAmount?number

Minimum order amount for free shipping. Omit for always free.

For type: LOCAL_PICKUP.

amountnumber

Pickup fee. Use 0 for free pickup.

pickupLocationobject
minDeliveryDays?integer

Minimum delivery time in business days.

Range0 <= value
maxDeliveryDays?integer

Maximum delivery time in business days.

Range0 <= value
handlingTime?integer

Internal handling time in business days.

Range1 <= value
requiresPickupPoint?boolean

Set true on a rate that delivers to a carrier pickup point (a partner shop or locker): the shopper must choose a point before paying. It is offered only to storefronts that can show the choice, and only while an installed shipping app lists points for the destination.

taxStatus?string

Whether shipping itself is taxable.

Value in"TAXABLE" | "NONE"
minOrderAmount?number

Minimum cart subtotal for this rate to be offered.

Range0 <= value
maxCost?number

Optional cap on the computed cost.

Range0 <= value
isActive?boolean

Whether this rate is offered.

platformSettings?object

Legacy per-platform overrides, keyed by platform code. Stored as-is; nothing reads them to push a rate to another platform.

classCosts?object

Per-shipping-class cost overrides.

classCalculationType?string

How classCosts are aggregated when the cart mixes classes.

Value in"per_class" | "per_order" | "per_item"
curl -X PATCH "https://api.brainerce.com/api/v1/shipping/zones/string/rates/string" \  -H "Idempotency-Key: string" \  -H "Content-Type: application/json" \  -d '{}'
{
  "id": "clx1a2b3c4d5e6f7g8h9",
  "zoneId": "clx1a2b3c4d5e6f7g8h9",
  "name": "Standard Shipping",
  "description": "Delivery in 3 to 5 business days",
  "type": "FLAT_RATE",
  "rateConfig": {
    "amount": 9.99
  },
  "minDeliveryDays": 3,
  "maxDeliveryDays": 5,
  "handlingTime": 1,
  "requiresPickupPoint": true,
  "taxStatus": "TAXABLE",
  "minOrderAmount": "200.00",
  "maxCost": "50.00",
  "classCosts": {},
  "classCalculationType": "per_class",
  "isActive": true,
  "platformSettings": {},
  "createdAt": "2019-08-24T14:15:22Z",
  "updatedAt": "2019-08-24T14:15:22Z"
}

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

Delete a shipping rate

Supports Idempotency-Key header for safe retries.

DELETE
/v1/shipping/zones/{zoneId}/rates/{rateId}
AuthorizationBearer <token>

Admin API key (server-to-server). Issue via the dashboard at Settings → API keys. Plain-text key is shown once — store in a secret manager. Format: Authorization: Bearer brainerce_xxxxxxxxx.

In: header

Path Parameters

zoneIdstring

Shipping Zone ID

rateIdstring

Shipping Rate ID

Header Parameters

Idempotency-Key?string

Client-supplied key (a UUID v4 is the recommended form, max 255 characters) that makes this mutation safe to retry.

  • Replay window: 24 hours. The first response for a key is cached; a retry inside the window with the same request body returns the original status and body without re-running the handler.
  • Reusing a key with a different body returns 409 Conflict with code: "IDEMPOTENCY_KEY_REUSED". The request fingerprint (method + path + body hash) is compared against the stored one; a mismatch is refused rather than served the old response.
  • Keys are scoped to the calling credential and store — two API keys may safely use the same key value.
  • Error responses are cached too, so a retry of a request that failed validation returns the same 400 immediately.
  • Sending this header on a GET returns 400 with code: "IDEMPOTENCY_KEY_NOT_SUPPORTED" — GETs are already idempotent.
  • Support is per-route and this parameter is the authoritative signal: a key sent to a route that does not declare it is accepted and silently ignored.

See /docs/api/idempotency.

Lengthlength <= 255
curl -X DELETE "https://api.brainerce.com/api/v1/shipping/zones/string/rates/string" \  -H "Idempotency-Key: string"
Empty

{
  "statusCode": 400,
  "code": "VALIDATION_FAILED",
  "message": "name should not be empty, price must be a positive number",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 401,
  "code": "UNAUTHORIZED",
  "message": "Invalid or expired credential",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/shipping/zones/{zoneId}/rates/{rateId}"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/v1/store"
}

List pickup locations

Lists the merchant pickup locations a shopper can collect an order from. Pair with checkout/{checkoutId}/delivery-type and pickup-location.

GET
/vc/{connectionId}/pickup-locations
X-Sales-Channel-Origin<token>

For /api/vc/{connectionId}/* routes the connectionId (vc_*) is in the URL path — not a header. Live-mode requests must also send a matching Origin header.

In: header

Path Parameters

connectionIdstring

Sales channel ID (vc_*), the canonical salesChannelId. connectionId is the deprecated name of the same value and is still the literal path segment.

Header Parameters

originstring

Origin of the storefront page making the call, for example https://shop.example.com. Required: a request with no Origin header is refused with 403. On a LIVE channel its host must equal the channel's registered domain (or one of its subdomains) or match an allowed origin. A TEST channel with no domain accepts any origin; once a domain is set it is matched as on LIVE.

X-SDK-Version?string

Version of the calling SDK (the Brainerce SDK sends it automatically). Informational: it is recorded on the channel and never changes the response.

curl -X GET "https://api.brainerce.com/api/vc/string/pickup-locations" \  -H "origin: string" \  -H "X-SDK-Version: string"
{
  "pickupLocations": [
    {
      "id": "clx1234567890",
      "name": "string",
      "rateName": "string",
      "address": {
        "line1": "5 Rothschild",
        "line2": "string",
        "city": "Tel Aviv",
        "region": "string",
        "postalCode": "6688218",
        "country": "IL"
      },
      "phone": "string",
      "hours": "string",
      "instructions": "string",
      "price": "0",
      "currency": "ILS"
    }
  ]
}

{
  "statusCode": 403,
  "code": "INSUFFICIENT_SCOPE",
  "message": "API key does not have the required scope: products:write",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/vc/{connectionId}/pickup-locations"
}

{
  "statusCode": 404,
  "code": "RESOURCE_NOT_FOUND",
  "message": "Resource not found",
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/vc/{connectionId}/pickup-locations"
}

{
  "statusCode": 429,
  "code": "RATE_LIMITED",
  "message": "Too many requests",
  "details": {
    "retryAfterSeconds": 12
  },
  "timestamp": "2026-08-23T10:15:00.000Z",
  "path": "/api/vc/{connectionId}/pickup-locations"
}