POST
Move a country into a market

Authorizations

Authorization
string
header
required

A secret API key. Publishable keys cannot reach this API. A key may carry an expiry, and an expired key is refused exactly like an unknown one, with a 401 that names no reason; check the key's expires_at in the dashboard rather than inferring it from a response. When a merchant rolls a key's secret they choose a grace window of up to 3 days, and for its duration BOTH the new secret and the one it replaced authenticate, so an integration moves over on its own deploy schedule instead of at the instant the button is pressed. Move before the window closes: after it, the old secret is refused. Nothing else about this contract moves with a roll. The key keeps its id and its scopes, so the only thing an integration updates is the credential itself.

Headers

Idempotency-Key
string
required

A unique key per logical write. Replaying a request with the same key returns the first response byte for byte instead of applying the write twice.

Path Parameters

regionId
string
required

Body

application/json

THE OPERATION A KEY HOLDING THIS GRANT PERFORMS MOST OFTEN, and the only route on this API that changes which currency an existing set of shoppers is quoted in without touching a single price. Everyone shopping from that country moves onto this region's currency and tax treatment at their next request. 200 WITH THE WHOLE REGION, not 201 with a membership object. The row created is a region-country assignment, and it is not addressable anywhere on this API: it has no GET, the read publishes only the code, and there is nothing to put in a Location header. The honest answer is the parent in the shape the reads already serve. ONE COUNTRY PER CALL. countries and country_codes are refused BY NAME, because a batch here would half-apply and then collide on the exclusivity rule and this family has no partial-failure contract to describe that. Send the whole list on POST /api/v1/regions, where it IS atomic, or call this route once per country. IT IS SAFE TO RETRY AND IT DOES NOT CONVERGE. Within the idempotency window a repeat returns the recorded 200. Past it, a repeat answers 409 country_already_assigned, because the unique index fires whether the country is already in THIS region or in another one and the refusal cannot tell those apart. Treat a 409 as "this assignment exists somewhere" and read GET /api/v1/regions to find where. THERE IS NO DETACH ROUTE. Removing a country leaves it in NO market, which empties the storefront's country dropdown for those shoppers and leaves their carts with no tax region to resolve, and it is the half of this pair that cannot be made to converge, since a repeated removal would answer not-found. apiscope mints no write_regions:delete to gate one with. Moving a country to another market is this same route pointed at the other region. THE STOREFRONT'S CACHED REGION LIST IS NOT DROPPED, unlike on the create, so a membership change reaches shoppers when that cache expires rather than instantly. The dashboard behaves the same way, which is why the gap is one honest behaviour rather than two. Nothing is emitted either: this family registers no webhook topics. No money moves and no stock moves. The region's updated_at DOES advance, in the same transaction, so a client polling that column to sync incrementally sees the most operationally significant change this resource has. region_id is refused BY NAME because the region is in the path, and the provenance keys and is_default for the create's reasons. No key may be null.

country_code
string
required

Required. The ISO 3166-1 alpha-2 code of the country to add: two ASCII letters, stored and returned lowercase, so "US" reads back "us". Anything else is a 400. A region already holding 250 countries answers 400 too_many_countries, and a region id that names nothing in this store is a generic 404.

Response

Success

data
object