Pamatjēdzieni
Daži principi attiecas uz visu API. Apgūstiet tos vienreiz, un katrs galapunkts darbosies tā, kā gaidāt.
#Jūsu un BoxLatvia identifikatori
Katrai lokācijai un telpai ir BoxLatvia id (uuid). Varat tai piešķirt arī savu external_id: līdz 100 rakstzīmēm, unikālu starp jūsu lokācijām vai telpām, iestatāmu vienreiz un pēc tam nemainīgu. Ar to varat:
- atrast objektus:
GET /v1/boxes?external_id=SKU-3M - izveidot vai atjaunināt vienā izsaukumā, neglabājot BoxLatvia identifikatorus:
PUT /v1/boxes/by-external-id/SKU-3M - norādīt telpas lokāciju:
"location_external_id": "WH-IMANTA"
Dažādi piegādātāji var lietot vienu un to pašu external id; tie nekad nesaduras.
#Atsauces kodi
Ērtības, rajoni un cenas mērvienības vienmēr tiek sūtīti un saņemti kā stabili kodi, piemēram, riga-imanta vai menesi, nekad kā nosaukumi vai identifikatori. Iegūstiet tos ar Atsauces datiem. Nezināms kods ir 422, kas nosauc problemātiskos kodus.
features ir kodu saraksts, kas aizvieto visu kopu. Sūtiet pilnu vēlamo sarakstu, nevis papildinājumus; sūtiet [], lai notīrītu.
#Nosacīti atjauninājumi
Katrs viena objekta GET atgriež ETag. Lai šo objektu mainītu vai dzēstu, nosūtiet to atpakaļ galvenē If-Match. Tas neļauj pārrakstīt izmaiņu, ko kāds cits veicis, piemēram, partneru portālā, pēc tam, kad nolasījāt objektu.
- Nav
If-Match→428 Precondition Required - Objekts mainīts pēc nolasīšanas →
412 Precondition Failed: nolasiet to vēlreiz un mēģiniet atkārtoti - Sūtiet vērtību tieši tādu, kādu saņēmāt (tā var izskatīties kā
W/"…") - Katra veiksmīga izmaiņa atgriež jauno
ETag
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"
}'const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3`, {
method: "PATCH",
headers: { Authorization: auth, "Content-Type": "application/json" },
body: JSON.stringify({
"address": "Kurzemes prospekts 3, Rīga"
}),
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.patch(
f"{API}/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
auth=(CLIENT_ID, CLIENT_SECRET),
json={
"address": "Kurzemes prospekts 3, Rīga",
},
)
print(r.status_code, r.json()){
"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"
}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"
}'const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3`, {
method: "PATCH",
headers: { Authorization: auth, "Content-Type": "application/json", "If-Match": "W/\"a15c541949287f3563009a45\"" },
body: JSON.stringify({
"address": "Cita adrese"
}),
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.patch(
f"{API}/v1/locations/9d80d5f4-d17a-4f3e-99f6-4ab43b132bc3",
auth=(CLIENT_ID, CLIENT_SECRET),
headers={"If-Match": "W/\"a15c541949287f3563009a45\""},
json={
"address": "Cita adrese",
},
)
print(r.status_code, r.json()){
"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"
}PUT …/by-external-id/… galapunktus: tiem If-Match nav vajadzīgs.#Droša atkārtošana
Pievienojiet galveni Idempotency-Key (1 līdz 200 drukājamas rakstzīmes, bez atstarpēm; ideāli der UUID) jebkuram POST, PUT, PATCH vai DELETE. Ja pieprasījumam beidzas gaidīšanas laiks, nosūtiet to vēlreiz ar to pašu atslēgu, un saņemsiet sākotnējo rezultātu ar atzīmi Idempotent-Replayed: true, nevis otru objektu.
- Tā pati atslēga, tas pats pieprasījums → tiek atkārtota saglabātā atbilde (glabājas 24 stundas)
- Tā pati atslēga, cits pieprasījums →
422 - Tā pati atslēga, kamēr pirmais izsaukums vēl darbojas →
409arRetry-After: 2
Katrai jaunai darbībai izmantojiet jaunu atslēgu, bet to pašu atslēgu — tikai tās pašas darbības atkārtojumiem.
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"
]
}'const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/locations`, {
method: "POST",
headers: { Authorization: auth, "Content-Type": "application/json", "Idempotency-Key": "ebfa60c9-5887-4526-9615-2d2ebdd9a0ed" },
body: JSON.stringify({
"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"
]
}),
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.post(
f"{API}/v1/locations",
auth=(CLIENT_ID, CLIENT_SECRET),
headers={"Idempotency-Key": "ebfa60c9-5887-4526-9615-2d2ebdd9a0ed"},
json={
"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",
],
},
)
print(r.status_code, r.json()){
"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"
}#Pārbaude bez saglabāšanas
Pievienojiet ?validate_only=true izveides, atjaunināšanas, dzēšanas, augšupielādes vai iesniegšanas pieprasījumam. API izpilda visas pārbaudes, tostarp datubāzes noteikumus, un parāda, kas notiktu, bet neko nesaglabā. Atbildē ir X-Validate-Only: true. Izmantojiet to jauna satura pārbaudei; atsevišķas testa vides nav.
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"
}'const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/locations?validate_only=true`, {
method: "POST",
headers: { Authorization: auth, "Content-Type": "application/json" },
body: JSON.stringify({
"name": "Mārupes noliktava",
"district": "marupes-novads-pinki"
}),
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.post(
f"{API}/v1/locations?validate_only=true",
auth=(CLIENT_ID, CLIENT_SECRET),
json={
"name": "Mārupes noliktava",
"district": "marupes-novads-pinki",
},
)
print(r.status_code, r.json()){
"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"
}#Lappušošana
Saraksta galapunkti atgriež lapas, vecākās pirmās, kā { "data": [...], "next_cursor": "..." }. Nododiet next_cursor atpakaļ kā ?cursor=… un beidziet, kad tas ir null. limit ir no 1 līdz 200 (noklusējums 50). Kursori ir necaurredzami: neveidojiet un nepētiet tos.
curl "$API/v1/locations?limit=2" \
-u "$CLIENT_ID:$CLIENT_SECRET"const API = "https://api.boxlatvia.lv";
const auth = "Basic " + btoa(`${CLIENT_ID}:${CLIENT_SECRET}`);
const res = await fetch(`${API}/v1/locations?limit=2`, {
headers: { Authorization: auth },
});
console.log(res.status, await res.json());import requests
API = "https://api.boxlatvia.lv"
r = requests.get(
f"{API}/v1/locations?limit=2",
auth=(CLIENT_ID, CLIENT_SECRET),
)
print(r.status_code, r.json()){
"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"
}#Pilnīgums: saraksts missing
API pieņem nepilnīgi aizpildītas lokācijas un telpas, lai jūs varētu tās veidot pakāpeniski. Katram objektam ir saraksts missing, kas norāda, kas vēl vajadzīgs:
| Objekts | Kas vajadzīgs | Vērtības missing |
|---|---|---|
| Lokācija | adrese, atrašanās vieta kartē, rajons un vismaz 5 ērtības, lai klienti to varētu atrast | address, coordinates, district, features |
| Telpa | apraksts, cena un cenas mērvienība, izmērs un vismaz viena ērtība, lai to varētu iesniegt izskatīšanai | description, price, price_unit, size, features |
#Publicēšana
Telpām ir status, ko nevar iestatīt tieši. Jūs varat lūgt izskatīšanu, un publicē BoxLatvia darbinieki.
Jebkurā brīdī withdraw atgriež telpu statusā DRAFT. Izmaiņas publicētā telpā (cena, pieejamība, teksts) mājaslapā parādās uzreiz; apstiprinājums vajadzīgs tikai statusa maiņai.
#Dzēšana
- Lokāciju, kurā ir telpas, nevar dzēst (
409). - Telpu ar pasūtījumiem nevar dzēst (
409): tā vietā iestatietavailable_unitsuz0, lai apturētu jaunas rezervācijas. - Dzēšot telpu vai lokāciju, tiek izdzēsti arī tās attēli.