On this page
- Endpoints
- List locations
- Query parameters
- Request
- Response 200
- Create a location
- Request body
- Request
- Response 201
- Get a location
- Request
- Response 200
- Update a location
- Request body
- Request
- Response 200
- Delete a location
- Request
- Response 204
- Set as default location
- Request
- Response 200
- Transfer inventory
- Request body
- Request
- Response 200
- Webhooks
- The location object
Locations
A location is a physical or logical place where a merchant holds inventory — a retail store, warehouse, popup, or the default online location. Every project gets a default location on creation. Inventory is tracked per variant per location via inventory_levels, with a denormalized total on the variant for backward compatibility.
The locations extension must be enabled to create or delete locations. The default location is always accessible regardless of extension state.
Base URL: https://api.hydrajs.dev
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/locations |
Secret | List locations |
POST |
/v1/locations |
Secret | Create a location |
GET |
/v1/locations/{id} |
Secret | Get a location |
PATCH |
/v1/locations/{id} |
Secret | Update a location |
DELETE |
/v1/locations/{id} |
Secret | Soft-delete a location |
POST |
/v1/locations/{id}/default |
Secret | Set as default location |
POST |
/v1/locations/{id}/transfer |
Secret | Transfer all inventory to another location |
List locations
GET /v1/locations
Returns a paginated list of locations. Soft-deleted locations are excluded.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit |
integer | 25 |
Results per page (1-100) |
cursor |
string | - | Pagination cursor from a previous response |
sort |
string | created_at |
Sort field: created_at, updated_at, name |
order |
string | desc |
Sort direction: asc, desc |
type |
string | - | Filter by type: retail, warehouse, popup, online |
active |
string | - | Filter by active status: true, false |
Request
curl "https://api.hydrajs.dev/v1/locations" \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 200
{
"data": [
{
"id": "loc_abc123def456ghi789",
"name": "Default",
"handle": "default",
"type": "online",
"is_default": true,
"is_active": true,
"metadata": null,
"address_line1": null,
"address_line2": null,
"city": null,
"state": null,
"postal_code": null,
"country": null,
"phone": null,
"email": null,
"created_at": "2026-08-28T12:00:00.000Z",
"updated_at": "2026-08-28T12:00:00.000Z"
}
],
"pagination": {
"cursor": null,
"has_more": false,
"total": 1
}
}
ℹPagination
All list endpoints use cursor-based pagination. Pass the cursor value from the response to fetch
the next page.
Create a location
POST /v1/locations
Creates a new location. Requires the locations extension to be enabled. New locations are always created with is_default: false.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Location name (1-255 chars) |
handle |
string | No | URL-friendly slug. Auto-generated from name if omitted |
type |
string | No | Location type: retail, warehouse, popup, online (default retail) |
address_line1 |
string | No | Street address (max 500 chars) |
address_line2 |
string | No | Apartment, suite, etc. (max 500 chars) |
city |
string | No | City (max 100 chars) |
state |
string | No | State or province (max 100 chars) |
postal_code |
string | No | Postal or ZIP code (max 20 chars) |
country |
string | No | ISO 3166-1 alpha-2 country code (2 letters) |
phone |
string | No | Contact phone (max 30 chars) |
email |
string | No | Contact email (max 255 chars) |
metadata |
object | No | Arbitrary key-value data |
Request
curl -X POST https://api.hydrajs.dev/v1/locations \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Birmingham Store",
"type": "retail",
"address_line1": "123 High St",
"city": "Birmingham",
"state": "West Midlands",
"postal_code": "B1 1AA",
"country": "GB",
"phone": "+441234567890",
"metadata": { "store_hours": "Mon-Sat 9-5" }
}'
Response 201
{
"data": {
"id": "loc_xyz789abc456def123",
"name": "Birmingham Store",
"handle": "birmingham-store",
"type": "retail",
"is_default": false,
"is_active": true,
"metadata": { "store_hours": "Mon-Sat 9-5" },
"address_line1": "123 High St",
"address_line2": null,
"city": "Birmingham",
"state": "West Midlands",
"postal_code": "B1 1AA",
"country": "GB",
"phone": "+441234567890",
"email": null,
"created_at": "2026-08-28T12:00:00.000Z",
"updated_at": "2026-08-28T12:00:00.000Z"
}
}
⚠Extension required
Creating a location requires the locations extension to be enabled. Returns 400 if the
extension is not active.
Get a location
GET /v1/locations/{id}
Returns a single location by ID.
Request
curl "https://api.hydrajs.dev/v1/locations/loc_xyz789abc456def123" \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 200
{
"data": {
"id": "loc_xyz789abc456def123",
"name": "Birmingham Store",
"handle": "birmingham-store",
"type": "retail",
"is_default": false,
"is_active": true,
"metadata": { "store_hours": "Mon-Sat 9-5" },
"address_line1": "123 High St",
"address_line2": null,
"city": "Birmingham",
"state": "West Midlands",
"postal_code": "B1 1AA",
"country": "GB",
"phone": "+441234567890",
"email": null,
"variant_count": 12,
"total_units": 350,
"created_at": "2026-08-28T12:00:00.000Z",
"updated_at": "2026-08-28T12:00:00.000Z"
}
}
Update a location
PATCH /v1/locations/{id}
Partially updates a location. All fields are optional — send only what changed. Cannot change is_default via PATCH; use the set default endpoint instead.
Request body
| Field | Type | Description |
|---|---|---|
name |
string | Location name (1-255 chars) |
handle |
string | URL-friendly slug |
type |
string | retail, warehouse, popup, online |
is_active |
boolean | Active state. Cannot deactivate the default location |
address_line1 |
string | null | Street address |
address_line2 |
string | null | Apartment, suite, etc. |
city |
string | null | City |
state |
string | null | State or province |
postal_code |
string | null | Postal or ZIP code |
country |
string | null | ISO 3166-1 alpha-2 code |
phone |
string | null | Contact phone |
email |
string | null | Contact email |
metadata |
object | null | Arbitrary key-value data. Set to null to clear |
Request
curl -X PATCH https://api.hydrajs.dev/v1/locations/loc_xyz789abc456def123 \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Birmingham Flagship",
"phone": "+449876543210"
}'
Response 200
Returns the full updated location object (same shape as Get a location).
Delete a location
DELETE /v1/locations/{id}
Soft-deletes a location. Requires the locations extension to be enabled. The handle is mutated to free the unique constraint.
Three conditions must be met:
- The location is not the default location
- The location is not the last active location
- The location has no remaining inventory — transfer inventory first via the transfer endpoint
Request
curl -X DELETE https://api.hydrajs.dev/v1/locations/loc_xyz789abc456def123 \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 204
Empty body.
⚠Transfer inventory first
If the location still has inventory levels, the request returns 400 with a message directing you
to transfer inventory first. Use POST /v1/locations/{id}/transfer before deleting.
Set as default location
POST /v1/locations/{id}/default
Sets the specified location as the default. The previous default is unset in the same transaction. Requires the locations extension to be enabled.
The target location must be active. If it is already the default, the response returns the location unchanged.
Request
curl -X POST https://api.hydrajs.dev/v1/locations/loc_xyz789abc456def123/default \
-H "Authorization: Bearer sk_live_YOUR_KEY"
Response 200
{
"data": {
"id": "loc_xyz789abc456def123",
"name": "Birmingham Store",
"handle": "birmingham-store",
"type": "retail",
"is_default": true,
"is_active": true,
"metadata": { "store_hours": "Mon-Sat 9-5" },
"address_line1": "123 High St",
"address_line2": null,
"city": "Birmingham",
"state": "West Midlands",
"postal_code": "B1 1AA",
"country": "GB",
"phone": "+441234567890",
"email": null,
"variant_count": 12,
"total_units": 350,
"created_at": "2026-08-28T12:00:00.000Z",
"updated_at": "2026-08-28T14:30:00.000Z"
}
}
Transfer inventory
POST /v1/locations/{id}/transfer
Transfers all inventory from this location to a destination location. Used before decommissioning a location. Requires the locations extension to be enabled.
The transfer runs in a single transaction: upserts destination inventory levels, deletes source levels, creates adjustment records, and syncs variant totals.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
destination_location_id |
string | Yes | ID of the location to receive the inventory |
Request
curl -X POST https://api.hydrajs.dev/v1/locations/loc_xyz789abc456def123/transfer \
-H "Authorization: Bearer sk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"destination_location_id": "loc_abc123def456ghi789"
}'
Response 200
{
"data": {
"transferred": 5
}
}
The transferred field indicates the number of inventory level rows moved.
ℹExisting destination inventory
If the destination already has inventory for a variant, the transferred quantity is added to the existing amount. No inventory is lost.
Webhooks
Location changes fire the following webhook events:
| Event | Trigger |
|---|---|
location.created |
A location is created |
location.updated |
A location is updated or set as default |
location.deleted |
A location is soft-deleted |
See Webhooks for subscription setup.
The location object
| Field | Type | Description |
|---|---|---|
id |
string | Unique ID (prefix: loc_) |
name |
string | Human-readable name |
handle |
string | URL-friendly slug, unique per project |
type |
string | retail, warehouse, popup, or online |
is_default |
boolean | Whether this is the default location |
is_active |
boolean | Whether the location can receive/deduct stock |
metadata |
object | null | Arbitrary merchant data |
address_line1 |
string | null | Street address |
address_line2 |
string | null | Apartment, suite, etc. |
city |
string | null | City |
state |
string | null | State or province |
postal_code |
string | null | Postal or ZIP code |
country |
string | null | ISO 3166-1 alpha-2 country code |
phone |
string | null | Contact phone |
email |
string | null | Contact email |
variant_count |
integer | Number of variants with inventory at this location |
total_units |
integer | Total inventory units across all variants at this location |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |