BoxLatviaDevelopers
Get access
API reference

Locations

A location is a place where you keep boxes. Customers find locations by district, address and amenities.

#The Location object

NameTypeDescription
iduuidBoxLatvia's identifier.
external_idstring | nullYour identifier, if you set one.
namestringName.
descriptionstring | nullDescription.
addressstring | nullStreet address.
districtstring | nullDistrict code.
district_namestring | nullThe district's name, for display.
latitudenumber | nullLatitude.
longitudenumber | nullLongitude.
box_countintegerHow many boxes the location has.
featuresstring[]Amenity codes.
missingstring[]What is still needed before customers can see the location: any of address, coordinates, district, features. Empty when complete.
created_atdatetimeISO 8601, UTC.
updated_atdatetimeISO 8601, UTC.
Example
{
  "id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
  "external_id": "WH-IMANTA",
  "name": "Imanta noliktava",
  "description": "Sausa, apsildāma noliktava ar 24/7 piekļuvi",
  "address": "Kurzemes prospekts 1, Rīga",
  "district": "riga-imanta",
  "district_name": "Rīga - Imanta",
  "latitude": 56.9496,
  "longitude": 24.0536,
  "box_count": 0,
  "features": [
    "24-7-piekluve",
    "apkure",
    "autostavvieta",
    "video-noverosana",
    "viedatslega"
  ],
  "missing": [],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T09:30:12.418Z"
}

#Endpoints

#List locations

GET/v1/locationslocations:read

Your locations, oldest first, one page at a time.

Query parameters

NameTypeDescription
limitintegerPage size, 1 to 200. Default 50.
cursorstringThe next_cursor of the previous page. Do not build cursors yourself.
external_idstringOnly the location with this identifier of yours.

Example

Two per page

The last page has "next_cursor": null.

curl "$API/v1/locations?limit=2" \
  -u "$CLIENT_ID:$CLIENT_SECRET"
200 OK
{
  "data": [
    {
      "id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
      "external_id": "WH-IMANTA",
      "name": "Imanta noliktava",
      "description": "Sausa, apsildāma noliktava ar 24/7 piekļuvi",
      "address": "Kurzemes prospekts 1, Rīga",
      "district": "riga-imanta",
      "district_name": "Rīga - Imanta",
      "latitude": 56.9496,
      "longitude": 24.0536,
      "box_count": 0,
      "features": [
        "24-7-piekluve",
        "apkure",
        "autostavvieta",
        "video-noverosana",
        "viedatslega"
      ],
      "missing": [],
      "created_at": "2026-11-07T09:30:12.418Z",
      "updated_at": "2026-11-07T09:30:12.418Z"
    },
    {
      "id": "4758ace9-4962-4906-bb6c-736ec772cb37",
      "external_id": null,
      "name": "Teika noliktava",
      "description": null,
      "address": null,
      "district": null,
      "district_name": null,
      "latitude": null,
      "longitude": null,
      "box_count": 0,
      "features": [],
      "missing": [
        "address",
        "coordinates",
        "district",
        "features"
      ],
      "created_at": "2026-11-07T09:30:12.418Z",
      "updated_at": "2026-11-07T09:30:12.418Z"
    }
  ],
  "next_cursor": "WyIyMDI2LTExLTA2IDEwOjAwOjAwLjAwMDAwMyswMCIsImE5NmM5NmQzLWFiMjAtNDYxYi1hZmExLTUwYWQ3YzU2ZTQ3ZSJd"
}

Errors

StatusWhen
400The cursor is not one returned by a previous response.

#Create a location

POST/v1/locationslocations:write

Creates a location. Only name is required: you can fill the rest in step by step; missing tells you what is left.

Query parameters

NameTypeDescription
validate_onlybooleantrue runs every check and returns what would happen, but saves nothing. See dry runs.

Headers

NameTypeDescription
Idempotency-KeystringOptional. 1 to 200 printable characters. A retry with the same key returns the original result instead of creating a duplicate. See safe retries.

Request body

NameTypeDescription
name requiredstringName of the location, up to 100 characters. Required when creating.
descriptionstring | nullUp to 250 characters.
addressstring | nullStreet address, up to 250 characters.
districtstring | nullDistrict code, see Reference data.
latitudenumber | null−90 to 90. Send together with longitude.
longitudenumber | null−180 to 180. Send together with latitude.
external_idstringYour own identifier, up to 100 characters, unique among your locations. Can be set once and then never changes.
featuresstring[]Amenity codes, see Reference data. Replaces the whole set; send [] to clear. At least 5 are needed before customers can find the location.

Examples

A complete location

The Location header and the ETag are returned with the new object.

curl -X POST "$API/v1/locations" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ebfa60c9-5887-4526-9615-2d2ebdd9a0ed" \
  -d '{
  "name": "Imanta noliktava",
  "external_id": "WH-IMANTA",
  "description": "Sausa, apsildāma noliktava ar 24/7 piekļuvi",
  "address": "Kurzemes prospekts 1, Rīga",
  "district": "riga-imanta",
  "latitude": 56.9496,
  "longitude": 24.0536,
  "features": [
    "24-7-piekluve",
    "apkure",
    "video-noverosana",
    "viedatslega",
    "autostavvieta"
  ]
}'
201 CreatedETag: W/"a15c541949287f3563009a45"Location: https://api.boxlatvia.lv/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3
{
  "id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
  "external_id": "WH-IMANTA",
  "name": "Imanta noliktava",
  "description": "Sausa, apsildāma noliktava ar 24/7 piekļuvi",
  "address": "Kurzemes prospekts 1, Rīga",
  "district": "riga-imanta",
  "district_name": "Rīga - Imanta",
  "latitude": 56.9496,
  "longitude": 24.0536,
  "box_count": 0,
  "features": [
    "24-7-piekluve",
    "apkure",
    "autostavvieta",
    "video-noverosana",
    "viedatslega"
  ],
  "missing": [],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T09:30:12.418Z"
}
Only a name

Everything still needed is listed in missing.

curl -X POST "$API/v1/locations" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Teika noliktava"
}'
201 CreatedETag: W/"ae068c091c4a3a43c47b4878"Location: https://api.boxlatvia.lv/v1/locations/4758ace9-4962-4906-bb6c-736ec772cb37
{
  "id": "4758ace9-4962-4906-bb6c-736ec772cb37",
  "external_id": null,
  "name": "Teika noliktava",
  "description": null,
  "address": null,
  "district": null,
  "district_name": null,
  "latitude": null,
  "longitude": null,
  "box_count": 0,
  "features": [],
  "missing": [
    "address",
    "coordinates",
    "district",
    "features"
  ],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T09:30:12.418Z"
}
Dry run

Same checks, nothing saved. The response carries X-Validate-Only: true.

curl -X POST "$API/v1/locations?validate_only=true" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Mārupes noliktava",
  "district": "marupes-novads-pinki"
}'
200 OKX-Validate-Only: true
{
  "id": "bf18a79f-f762-4775-a17d-5ffa0623ebd7",
  "external_id": null,
  "name": "Mārupes noliktava",
  "description": null,
  "address": null,
  "district": "marupes-novads-pinki",
  "district_name": "Mārupes novads - Piņķi",
  "latitude": null,
  "longitude": null,
  "box_count": 0,
  "features": [],
  "missing": [
    "address",
    "coordinates",
    "features"
  ],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T09:30:12.418Z"
}
Invalid values

Every problem is reported at once.

curl -X POST "$API/v1/locations" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "",
  "latitude": 95,
  "longitude": 24.0536
}'
422 Unprocessable Content
{
  "type": "https://api.boxlatvia.lv/problems/validation-failed",
  "title": "Validation failed",
  "status": 422,
  "detail": "One or more fields are invalid.",
  "request_id": "5f22a099-b84d-48eb-b078-6c5423a2175e",
  "errors": [
    {
      "field": "name",
      "message": "must not be empty"
    },
    {
      "field": "latitude",
      "message": "Number must be less than or equal to 90"
    }
  ]
}
Unknown codes
curl -X POST "$API/v1/locations" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Centra noliktava",
  "district": "atlantis",
  "features": [
    "24-7-piekluve",
    "sauna"
  ]
}'
422 Unprocessable Content
{
  "type": "https://api.boxlatvia.lv/problems/validation-failed",
  "title": "Validation failed",
  "status": 422,
  "detail": "One or more fields are invalid.",
  "request_id": "a52756bd-76c1-4887-9100-0e46deb7de27",
  "errors": [
    {
      "field": "district",
      "message": "is not a known district code"
    },
    {
      "field": "features",
      "message": "unknown or inactive feature code(s): sauna"
    }
  ]
}
Your id is already used

The answer names the existing location in existing_id.

curl -X POST "$API/v1/locations" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Cita noliktava",
  "external_id": "WH-IMANTA"
}'
409 Conflict
{
  "type": "https://api.boxlatvia.lv/problems/duplicate-external-id",
  "title": "Conflict",
  "status": 409,
  "detail": "A location with this external_id already exists.",
  "request_id": "8d45de36-bd83-4dcf-b271-0e25822b5a2b",
  "existing_id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
  "existing": "https://api.boxlatvia.lv/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3"
}

Errors

StatusWhen
409external_id is already used by another of your locations.
422A value is invalid, or a district or feature code is unknown.

#Retrieve a location

GET/v1/locations/{id}locations:read

One location. The response carries the ETag you need to change or delete it.

Path parameters

NameTypeDescription
iduuidThe location's BoxLatvia id.

Example

Retrieve
curl "$API/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3" \
  -u "$CLIENT_ID:$CLIENT_SECRET"
200 OKETag: W/"a15c541949287f3563009a45"
{
  "id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
  "external_id": "WH-IMANTA",
  "name": "Imanta noliktava",
  "description": "Sausa, apsildāma noliktava ar 24/7 piekļuvi",
  "address": "Kurzemes prospekts 1, Rīga",
  "district": "riga-imanta",
  "district_name": "Rīga - Imanta",
  "latitude": 56.9496,
  "longitude": 24.0536,
  "box_count": 0,
  "features": [
    "24-7-piekluve",
    "apkure",
    "autostavvieta",
    "video-noverosana",
    "viedatslega"
  ],
  "missing": [],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T09:30:12.418Z"
}

Errors

StatusWhen
404No such location of yours.

#Update a location

PATCH/v1/locations/{id}locations:write

Changes only the fields you send. external_id can be set once and then never changes.

Path parameters

NameTypeDescription
iduuidThe location's BoxLatvia id.

Query parameters

NameTypeDescription
validate_onlybooleantrue runs every check and returns what would happen, but saves nothing. See dry runs.

Headers

NameTypeDescription
If-Match requiredstringThe ETag from a previous GET, exactly as received. 428 if missing, 412 if the object changed since. See conditional updates.

Request body (any of the fields)

NameTypeDescription
name requiredstringName of the location, up to 100 characters. Required when creating.
descriptionstring | nullUp to 250 characters.
addressstring | nullStreet address, up to 250 characters.
districtstring | nullDistrict code, see Reference data.
latitudenumber | null−90 to 90. Send together with longitude.
longitudenumber | null−180 to 180. Send together with latitude.
external_idstringYour own identifier, up to 100 characters, unique among your locations. Can be set once and then never changes.
featuresstring[]Amenity codes, see Reference data. Replaces the whole set; send [] to clear. At least 5 are needed before customers can find the location.

Examples

Update address and description
curl -X PATCH "$API/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "If-Match: W/\"a15c541949287f3563009a45\"" \
  -d '{
  "address": "Kurzemes prospekts 3, Rīga",
  "description": "Sausa, apsildāma noliktava ar uzbrauktuvi"
}'
200 OKETag: W/"690d868c2dd969cc637a8941"
{
  "id": "9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
  "external_id": "WH-IMANTA",
  "name": "Imanta noliktava",
  "description": "Sausa, apsildāma noliktava ar uzbrauktuvi",
  "address": "Kurzemes prospekts 3, Rīga",
  "district": "riga-imanta",
  "district_name": "Rīga - Imanta",
  "latitude": 56.9496,
  "longitude": 24.0536,
  "box_count": 0,
  "features": [
    "24-7-piekluve",
    "apkure",
    "autostavvieta",
    "video-noverosana",
    "viedatslega"
  ],
  "missing": [],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T14:05:41.092Z"
}
Without If-Match
curl -X PATCH "$API/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "address": "Kurzemes prospekts 3, Rīga"
}'
428 Precondition Required
{
  "type": "https://api.boxlatvia.lv/problems/precondition-required",
  "title": "Precondition required",
  "status": 428,
  "detail": "Send the current version in an If-Match header (the ETag from a GET of this resource).",
  "request_id": "f61a59eb-da5b-4d6f-8308-caa9ddd62ba6"
}
With an outdated ETag

Someone changed the location after you read it. Read it again and retry.

curl -X PATCH "$API/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -H "If-Match: W/\"a15c541949287f3563009a45\"" \
  -d '{
  "address": "Cita adrese"
}'
412 Precondition Failed
{
  "type": "https://api.boxlatvia.lv/problems/precondition-failed",
  "title": "Precondition failed",
  "status": 412,
  "detail": "The resource changed since you read it. GET it again and retry with the new ETag.",
  "request_id": "98ae51e1-6505-43f4-8589-b524d2dd65c2"
}

Errors

StatusWhen
404No such location of yours.
412The location changed since you read it.
422A value is invalid, or external_id was already set.
428If-Match is missing.

#Create or update by your own id

PUT/v1/locations/by-external-id/{external_id}locations:write

Creates the location if your id is new, otherwise updates the fields you send. No If-Match is needed: meant for feeds that should win.

Path parameters

NameTypeDescription
external_idstringYour identifier for the location.

Query parameters

NameTypeDescription
validate_onlybooleantrue runs every check and returns what would happen, but saves nothing. See dry runs.

Request body

NameTypeDescription
name requiredstringName of the location, up to 100 characters. Required when creating.
descriptionstring | nullUp to 250 characters.
addressstring | nullStreet address, up to 250 characters.
districtstring | nullDistrict code, see Reference data.
latitudenumber | null−90 to 90. Send together with longitude.
longitudenumber | null−180 to 180. Send together with latitude.
external_idstringYour own identifier, up to 100 characters, unique among your locations. Can be set once and then never changes.
featuresstring[]Amenity codes, see Reference data. Replaces the whole set; send [] to clear. At least 5 are needed before customers can find the location.

Examples

First call: created (201)

A new location needs a name.

curl -X PUT "$API/v1/locations/by-external-id/WH-PINKI" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Piņķu noliktava",
  "address": "Priedaines iela 19, Piņķi",
  "district": "marupes-novads-pinki"
}'
201 CreatedETag: W/"5d85e2db7390f6d8fe61025f"Location: https://api.boxlatvia.lv/v1/locations/154ab2ad-0419-4cb2-a214-cc8d5e8b032c
{
  "id": "154ab2ad-0419-4cb2-a214-cc8d5e8b032c",
  "external_id": "WH-PINKI",
  "name": "Piņķu noliktava",
  "description": null,
  "address": "Priedaines iela 19, Piņķi",
  "district": "marupes-novads-pinki",
  "district_name": "Mārupes novads - Piņķi",
  "latitude": null,
  "longitude": null,
  "box_count": 0,
  "features": [],
  "missing": [
    "coordinates",
    "features"
  ],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T09:30:12.418Z"
}
Second call: updated (200)

Only the fields you send change.

curl -X PUT "$API/v1/locations/by-external-id/WH-PINKI" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/json" \
  -d '{
  "description": "Jauna noliktava ar uzbrauktuvi"
}'
200 OKETag: W/"3af8176ea6ccd30a1434aa5d"
{
  "id": "154ab2ad-0419-4cb2-a214-cc8d5e8b032c",
  "external_id": "WH-PINKI",
  "name": "Piņķu noliktava",
  "description": "Jauna noliktava ar uzbrauktuvi",
  "address": "Priedaines iela 19, Piņķi",
  "district": "marupes-novads-pinki",
  "district_name": "Mārupes novads - Piņķi",
  "latitude": null,
  "longitude": null,
  "box_count": 0,
  "features": [],
  "missing": [
    "coordinates",
    "features"
  ],
  "created_at": "2026-11-07T09:30:12.418Z",
  "updated_at": "2026-11-07T14:05:41.092Z"
}

Errors

StatusWhen
422A value is invalid, or the body contains a different external_id.

#Delete a location

DELETE/v1/locations/{id}locations:write

Deletes the location and its pictures. Refused while it still has boxes.

Path parameters

NameTypeDescription
iduuidThe location's BoxLatvia id.

Query parameters

NameTypeDescription
validate_onlybooleantrue runs every check and returns what would happen, but saves nothing. See dry runs.

Headers

NameTypeDescription
If-Match requiredstringThe ETag from a previous GET, exactly as received. 428 if missing, 412 if the object changed since. See conditional updates.

Examples

Deleted
curl -X DELETE "$API/v1/locations/2a8487f7-145e-40c0-ac01-c918a2f7c759" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "If-Match: W/\"d7761dc4eb50ce8a08ae74d4\""
204 No Content
No response body
Still has boxes
curl -X DELETE "$API/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3" \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "If-Match: W/\"690d868c2dd969cc637a8941\""
409 Conflict
{
  "type": "https://api.boxlatvia.lv/problems/location-has-boxes",
  "title": "Conflict",
  "status": 409,
  "detail": "This location still has 2 box(es). Delete or move them first.",
  "request_id": "fa8d71d9-3e96-420a-b803-839b592d6a56",
  "box_count": 2
}

Errors

StatusWhen
404No such location of yours.
409The location still has boxes: delete or move them first.
412The location changed since you read it.
428If-Match is missing.