Country States
A country state is any sub-division of a country — state, province, territory, prefecture, etc. Each state belongs to exactly one country and identifies itself with a short code (AL, CA, BC, MH, …).
Endpoints
The same resource is exposed under two URL shapes so clients can choose the access pattern that fits their UI:
| Method | Path | Purpose |
|---|---|---|
| GET | /api/shop/countries/{country_id}/states | Nested — every state for a single country (recommended for cascade pickers) |
| GET | /api/shop/countries/{country_id}/states/{id} | Nested — single state, scoped to its parent country |
| GET | /api/shop/country-states | Flat — every state across every country in one paginated stream |
| GET | /api/shop/country-states/{id} | Flat — single state by global ID |
Two things hold across all four:
- The response shape is identical — only the URL and its scoping differ. Use the example switcher above the curl block to flip through them.
- State IDs come from one global sequence, so
id: 66is Alberta whether you reach it through/countries/40/states/66or/country-states/66.
When to use which
| Scenario | Endpoint |
|---|---|
| Country/state cascade dropdown in a checkout form | GET /api/shop/countries/{country_id}/states |
| Resolve a single state ID (e.g. stored on an order address) | GET /api/shop/country-states/{id} |
| Build an offline cache of every state in the world | GET /api/shop/country-states (paginate through) |
| Validate that a state belongs to a specific country | GET /api/shop/countries/{country_id}/states/{id} (404 if mismatched) |
Request Headers
| Header | Required | Description |
|---|---|---|
Accept | Yes | application/json |
X-STOREFRONT-KEY | Yes | Storefront API key (pk_storefront_…) |
Query Parameters (collections only)
| Parameter | Type | Default | Description |
|---|---|---|---|
page | integer | 1 | Page number (1-based) |
per_page | integer | 10 | Items per page. Max 50. |
Pagination headers (X-Total-Count, X-Page, X-Per-Page, X-Total-Pages) are emitted on both collection variants. See Pagination.
State Object Fields
| Field | Type | Description |
|---|---|---|
id | integer | State primary key (globally unique across countries) |
countryId | integer | Owning country ID |
countryCode | string | ISO country code of the parent (CA, US, …) |
code | string | State/province code within the country (AB, CA, MH, …) |
defaultName | string | Default English name |
translations | array of path references | One reference per locale. Fetch GET /api/shop/country_state_translations/{id} to read one. Countries inline their translations, but states do not — keeping the flat 586-row collection lean. See IRIs & HATEOAS. |
Use Cases
- Render a state/province dropdown that depends on the chosen country (use the nested collection).
- Validate a
state_idsaved on an order against itscountry_id(use the nested single — 404 means mismatched). - Resolve a localized state name for a given customer locale by following one of the
translations[]IRIs. - Bulk-export every state for a CSV / SPA cache (use the flat collection with
?per_page=50).
Best Practices
- Prefer the nested route for a picker —
/api/shop/countries/{countryId}/statesreturns just that country's states, while this flat collection pages through every state in the world. - Match on
code, not on the display name — checkout stores the state code, and names change with the request locale. - Cache alongside the country list — the data is static reference data.
Related Resources
- Countries — the parent resource; emits the same state objects inline under
Country.states[] - Introduction → IRIs & HATEOAS — how to dereference the path references in these payloads

