Kaj Kolio REST API omogoča?
Kolio REST API je vmesnik HTTP/JSON pod osnovnim naslovom https://kolio.si/api/integrations/v1, prek katerega zunanji sistem bere in spreminja termine (koledar), CRM kontakte in naloge enega računa Kolio; avtenticira se z API ključem, ki hkrati določa račun (tenant) in dovoljeni obseg.
Vsi trije vhodi — vmesnik aplikacije, REST API in MCP strežnik — pišejo skozi ista poslovna jedra. Termin, ustvarjen prek API-ja, gre skozi isto preverjanje delovnega časa lokacije, prostih izvajalcev in prekrivanja kot termin, ki ga vaša ekipa vpiše v koledar; naloga dobi enako časovnico kot v CRM-ju. Integracija zato ne more ustvariti zapisa, ki ga aplikacija ne bi dovolila.
| Področje | Kaj lahko počnete | Obseg (scope) |
|---|---|---|
| Termini (koledar) | seznam po obdobju, en termin, ustvarjanje, premik/sprememba, preklic, trajni izbris | bookings:read, bookings:write |
| Kontakti (CRM) | seznam in iskanje, en kontakt z opombami, ustvarjanje, sprememba z opombo, izbris | contacts:read, contacts:write |
| Naloge (CRM) | seznam s filtri, ena naloga s časovnico, ustvarjanje, sprememba s komentarjem, izbris | tasks:read, tasks:write |
| Webhooki | potisna obvestila o dogodkih na vaš URL, podpisana s HMAC-SHA256 | ni obsega — nastavijo se v aplikaciji |
Pogovori, poročila in baza znanja imajo svoje obsege, a v REST v1 zanje ni končnih točk. Lokacije (poslovalnice z delovnim časom) vrne GET /locations z obsegom services:read; storitve so dosegljive prek orodja list_services na MCP strežniku.
Kako ustvarim API ključ?
API ključ ustvari član z dovoljenjem Nastavitve na strani Nastavitve → MCP viri in integracije, v razdelku API ključi; ključ se v celoti prikaže samo enkrat, v bazi pa ostane le njegov zgoščeni odtis (SHA-256) in vidna predpona.
Odprite nastavitve integracij
V meniju izberite Nastavitve → MCP viri in integracije. Zgornji del strani, Kolio kot vir za zunanje sisteme, vsebuje razdelka API ključi in Webhooki.
Nastavitve → MCP viri in integracijePoimenujte ključ
V polje Ime ključa vpišite, kateri sistem ga bo uporabljal (npr.
ERP integracija). Ime se zapiše v revizijsko sled: v časovnici naloge in pri opombah kontakta se sprememba prek API-ja prikaže kotapi:ERP integracija, ne kot ime osebe.Omejite obsege
Pod Obsegi (scopes) označite obsege, ki jih integracija potrebuje, npr.
contacts:readinbookings:write. Ključ nikoli ne preseže vaših dovoljenj v tem računu: obsegi, za katere nimate ustreznega dovoljenja, so onemogočeni, in če jih zahtevate mimo obrazca, Kolio ključa ne ustvari in navede zavrnjene obsege. Če ne označite ničesar, ključ dobi vse obsege, ki jih smete izdati vi — vedno kot izpisan seznam, ne*. Priporočamo najmanjši nabor, ki ga integracija potrebuje.Ustvarite in shranite ključ
Kliknite Ustvari ključ. Prikaže se okvir Ključ je ustvarjen z opozorilom Shranite ga zdaj — prikazan je samo enkrat. Kopirajte celoten niz
kolio_sk_…v skrivnostno shrambo vašega sistema. Po osvežitvi strani je viden le še začetek ključa (predpona).Preverite ključ
Pokličite končno točko
GET /ping(primer v naslednjem razdelku). Odgovor vrne id računa in obsege ključa.
Kako se avtenticiram?
Ključ pošljete v glavi Authorization: Bearer kolio_sk_… ali v glavi X-API-Key: kolio_sk_…; račun (tenant) se vedno določi iz ključa in nikoli iz telesa ali URL-ja zahteve, zato en ključ ne more doseči podatkov drugega računa.
curl -s https://kolio.si/api/integrations/v1/ping \
-H "Authorization: Bearer kolio_sk_…"
# odgovor
{
"ok": true,
"tenantId": "…",
"scopes": ["contacts:read", "bookings:write"],
"timestamp": "2026-09-15T08:12:03.512Z"
}/ping je edina končna točka, ki odgovora ne ovije v data.Vse ostale končne točke vrnejo ob uspehu objekt { "data": … }, ob napaki pa { "error": "koda", "message": "slovensko pojasnilo" }. Koda napake je stabilna in primerna za programsko obravnavo, sporočilo je namenjeno ljudem.
| HTTP | Koda (error) | Kdaj |
|---|---|---|
| 401 | unauthorized | ključ manjka, ni veljaven ali je preklican |
| 403 | insufficient_scope | ključ nima obsega, ki ga končna točka zahteva (v sporočilu je naveden manjkajoči obseg) |
| 403 | plan_feature | paket računa ne vključuje REST API-ja (pri MCP strežniku: funkcije MCP strežnik); sporočilo navede paket, od katerega je funkcija na voljo |
| 403 | tenant_inactive | naročnina ali preizkusno obdobje računa ni več aktivno — ključ je veljaven, a se do obnovitve zavrne |
| 400 | invalid_json | telo zahteve ni veljaven JSON |
| 422 | invalid_body | telo ne ustreza shemi; sporočilo navede prvo neveljavno polje |
| 404 | not_found | zapis z danim id-jem ne obstaja v tem računu |
| 422 | no_changes | pri PATCH ni podanega nobenega polja za spremembo |
Obsegi (scopes) in dovoljenja
Vsak obseg API ključa je preslikan v obstoječe dovoljenje člana v Koliu, zato ključ nikoli ne odpre področja, ki ga aplikacija sama ne pozna; obsegi so natančni nizi brez hierarhije — contacts:write ne vključuje contacts:read.
| Obseg | Kaj pokriva | Ustrezno dovoljenje člana | Spreminja podatke |
|---|---|---|---|
bookings:read | branje terminov (koledar) | Termini | ne |
bookings:write | ustvarjanje, sprememba, preklic in izbris terminov | Termini | da |
services:read | branje storitev (MCP) in lokacij (GET /locations) | Storitve | ne |
contacts:read | branje kontaktov in njihovih opomb | Kontakti | ne |
contacts:write | ustvarjanje, sprememba, opombe in izbris kontaktov | Kontakti | da |
tasks:read | branje nalog in njihove časovnice | Naloge | ne |
tasks:write | ustvarjanje, sprememba, komentarji in izbris nalog | Naloge | da |
conversations:read | pogovori in transkripti | Pogovori | ne |
reports:read | poročila | Poročila | ne |
knowledge:read | baza znanja | Baza znanja | ne |
email:write | pošiljanje e-pošte v vašem imenu | E-poštni marketing | da |
Za conversations:read, reports:read, knowledge:read in email:write v REST v1 trenutno ni končnih točk. email:write namerno ni v privzetem naboru MCP konektorja.
Katere končne točke so na voljo?
Integrations API v1 ima osem poti: ping, locations ter po dve za termine, kontakte in naloge — zbirka (GET seznam, POST ustvarjanje) in posamezen zapis (GET, PATCH, DELETE); seznami so omejeni s parametrom limit (privzeto 50, največ 200).
| Metoda in pot | Kaj naredi | Obseg | Parametri / polja |
|---|---|---|---|
GET /ping | preveri ključ | katerikoli | — |
GET /locations | aktivne lokacije z naslovom in delovnim časom (hours: weekday 0 = nedelja … 6 = sobota, startTime/endTime HH:MM v pasu naročnika) | services:read | includeInactive=1 |
GET /bookings | seznam terminov, najnovejši prvi; vsak termin ima locationId in locationName | bookings:read | from, to (ISO 8601), limit |
POST /bookings | ustvari termin; sproži booking.created | bookings:write | slotStart* in eno od serviceId / durationMin / slotEnd; contactId, title, notes, assigneeEmail, locationId (obvezen pri več lokacijah, sicer jedro izbere lokacijo, kjer je termin mogoč) |
GET /bookings/{id} | en termin | bookings:read | — |
PATCH /bookings/{id} | premik, sprememba ali preklic (status: cancelled sproži booking.cancelled) | bookings:write | slotStart, slotEnd, serviceId, contactId, title, notes, assigneeEmail, locationId, status |
DELETE /bookings/{id} | trajno izbriše termin | bookings:write | — |
GET /contacts | seznam / iskanje kontaktov | contacts:read | q, email, phone, externalId, limit |
POST /contacts | ustvari kontakt; sproži contact.created | contacts:write | vsaj eno od firstName, lastName, email, phone; company, notes, tags, externalId, gdprConsent, marketingConsent |
GET /contacts/{id} | kontakt z opombami (notes[]) | contacts:read | — |
PATCH /contacts/{id} | delna sprememba; note pripne opombo | contacts:write | ista polja kot POST + note |
DELETE /contacts/{id} | trajno izbriše kontakt (npr. GDPR zahteva) | contacts:write | — |
GET /tasks | seznam nalog | tasks:read | status, assigneeEmail, contactId, q, limit |
POST /tasks | ustvari nalogo; sproži task.created | tasks:write | title*; description, assigneeEmail, contactId, priority, dueAt, status |
GET /tasks/{id} | naloga s časovnico (events[]) | tasks:read | — |
PATCH /tasks/{id} | delna sprememba; comment doda komentar; sproži task.updated | tasks:write | ista polja kot POST + comment |
DELETE /tasks/{id} | trajno izbriše nalogo s časovnico | tasks:write | — |
Zvezdica pomeni obvezno polje. Pri PATCH nenavedena polja ostanejo nespremenjena; null (pri nalogah tudi prazen niz) polje izprazni.
Termini
curl -s -X POST https://kolio.si/api/integrations/v1/bookings \
-H "Authorization: Bearer kolio_sk_…" \
-H "Content-Type: application/json" \
-d '{
"slotStart": "2026-09-22T09:00",
"serviceId": "<id storitve>",
"contactId": "<id kontakta>",
"locationId": "<id lokacije iz GET /locations>",
"notes": "Rezervacija iz spletne trgovine"
}'
# 201
{ "data": { "id": "…", "slotStart": "2026-09-22T07:00:00.000Z",
"slotEnd": "2026-09-22T07:30:00.000Z", "status": "confirmed",
"serviceId": "…", "contactId": "…", "locationId": "…", "locationName": "Ljubljana",
"source": "api", "…": "…" } }
# 422 — izven delovnega časa lokacije, ni prostega izvajalca ali nosilec ni član
{ "error": "booking_rejected", "message": "Termin je izven delovnega časa lokacije." }201.Seznam prostih terminov REST v1 ne ponuja; proste ure vrne orodje find_free_slots na MCP strežniku. Zasedenost lahko preverite tudi z GET /bookings?from=…&to=… in delovnim časom lokacij iz GET /locations, ki ga nastavite v koledarju in storitvah. Zapis prek API-ja je strog: termin izven delovnega časa lokacije ali brez prostega izvajalca vrne 422 booking_rejected; izjeme lahko vpiše samo ekipa v koledarju.
| HTTP | Koda | Kdaj |
|---|---|---|
| 422 | missing_duration | POST brez serviceId, durationMin in slotEnd |
| 422 | invalid_slot | slotStart ali slotEnd ni veljaven ISO 8601 čas |
| 422 | invalid_range | from ali to pri GET ni veljaven čas |
| 422 | booking_rejected | jedro je termin zavrnilo: zaseden termin, neznan nosilec, neveljavna storitev |
Kontakti
curl -s -X POST https://kolio.si/api/integrations/v1/contacts \
-H "X-API-Key: kolio_sk_…" \
-H "Content-Type: application/json" \
-d '{
"firstName": "Ana",
"lastName": "Novak",
"email": "ana.novak@example.com",
"phone": "+38640123456",
"externalId": "erp-10482",
"tags": ["spletna-trgovina"],
"gdprConsent": true
}'
# 201
{ "data": { "id": "…", "firstName": "Ana", "lastName": "Novak",
"email": "ana.novak@example.com", "externalId": "erp-10482", "…": "…" } }
# 422
{ "error": "missingFields",
"message": "Kontakt potrebuje vsaj eno od polj: ime, priimek, telefon ali e-pošta." }gdprConsent: true zabeleži privolitev z današnjim datumom in virom api.Pred ustvarjanjem preverite, ali kontakt že obstaja: GET /contacts?email=…, ?phone=… ali ?externalId=… vrnejo točno ujemanje, ?q=… išče po imenu, priimku, e-pošti, telefonu in podjetju. Polje externalId je namenjeno id-ju stranke v vašem sistemu (ERP, spletna trgovina).
Naloge
# POST — nova naloga
curl -s -X POST https://kolio.si/api/integrations/v1/tasks \
-H "Authorization: Bearer kolio_sk_…" \
-H "Content-Type: application/json" \
-d '{
"title": "Pokliči stranko glede ponudbe 2026-118",
"contactId": "<id kontakta>",
"assigneeEmail": "prodaja@vase-podjetje.si",
"priority": 2,
"dueAt": "2026-09-18T12:00"
}'
# 201
{ "data": { "id": "tsk_…", "title": "Pokliči stranko …", "status": "nova",
"priority": 2, "dueAt": "2026-09-18T10:00:00.000Z", "…": "…" } }
# PATCH — zaključi nalogo s komentarjem
curl -s -X PATCH https://kolio.si/api/integrations/v1/tasks/tsk_… \
-H "Authorization: Bearer kolio_sk_…" \
-H "Content-Type: application/json" \
-d '{ "status": "zakljucena", "comment": "Stranka je ponudbo potrdila." }'
# 422 — neznan nosilec
{ "error": "unknownAssignee", "message": "…" }api: + ime ključa.| Polje | Dovoljene vrednosti | Opomba |
|---|---|---|
status | nova, v_teku, v_cakanju, zakljucena, arhivirana | za ohranitev sledi raje arhivirana kot DELETE |
priority | celo število 0–3 | vrednosti zunaj razpona se omejijo |
assigneeEmail | e-pošta aktivnega člana računa | null ali prazen niz sprosti nalogo; neznan naslov → unknownAssignee |
dueAt | ISO 8601 ali samo datum YYYY-MM-DD | null ali prazen niz odstrani rok; neveljaven → invalid_due |
Kako API razume čas?
Vsi časi vhoda so ISO 8601; niz z odmikom ali Z se vzame dobesedno, niz brez odmika (2026-09-22T09:00) pa se razume kot lokalni čas v časovnem pasu vašega računa (Nastavitve → Splošno, privzeto Europe/Ljubljana), sam datum (2026-09-22) pa kot polnoč tega dne v istem pasu.
Odgovori vračajo čase kot UTC instant s končnico Z (npr. 2026-09-22T07:00:00.000Z). Strežnik teče v UTC; brez tega pravila bi se termin, poslan kot 09:00 brez odmika, tiho premaknil za eno ali dve uri. Pravilo velja za slotStart, slotEnd, from, to in dueAt.
Kako delujejo webhooki?
Webhook je HTTP POST, ki ga Kolio ob dogodku pošlje na vaš URL z JSON ovojnico { event, tenantId, timestamp, data }, podpisano s HMAC-SHA256 (RFC 2104) v glavi X-Kolio-Signature (oblika sha256= + šestnajstiški HMAC); čas dogodka je v glavi X-Kolio-Timestamp in v polju timestamp telesa, zato je podpis vezan na čas. Pošiljanje je enkratno in po načelu najboljšega truda (brez ponovnih poskusov).
Pripravite sprejemni URL
Na vašem strežniku pripravite pot, ki sprejme POST z JSON telesom in odgovori v manj kot 10 sekundah (Kolio po 10 s zahtevo prekine). Naslov mora začeti s
http://alihttps://; za produkcijo uporabite HTTPS.Dodajte webhook
V razdelku Webhooki vpišite URL naslov in pod Dogodki označite dogodke, ki jih želite prejemati (npr.
Nastavitve → MCP viri in integracije → Webhookibooking.createdincall.completed). Če ne označite ničesar, webhook prejema vse dogodke. Kliknite Dodaj webhook.Preverite podpis
Ob ustvarjanju Kolio prikaže skrivnost
whsec_…v okvirju Skrivnost webhooka — samo enkrat; shranite jo v skrivnostno shrambo svojega sistema, v seznamu je pozneje vidnih le prvih nekaj znakov. Z njo Kolio podpiše vsako zahtevo: izračunajte HMAC-SHA256 nad surovim telesom in rezultat primerjajte z glavoX-Kolio-Signature(primer spodaj). Če v telesu ali glaviX-Kolio-Timestamppreverite še starost dogodka (npr. največ 5 minut), zavrnete tudi ponovljene zahteve.Upravljajte webhook
V seznamu je pri vsakem webhooku stanje aktiven / neaktiven; gumb Izklopi pošiljanje začasno ustavi, Izbriši ga odstrani. Neaktivni webhook dogodkov ne prejema. Gumb Rotiraj skrivnost ustvari novo skrivnost in jo prikaže enkrat; stara neha veljati takoj, zato jo na svojem strežniku zamenjajte sočasno — dogodki med rotacijo in zamenjavo podpisa ne prestanejo.
| Dogodek | Kdaj se sproži | Polja v data |
|---|---|---|
booking.created | termin ustvarjen prek REST ali MCP | bookingId, contactId, serviceId, slotStart, slotEnd, status |
booking.cancelled | termin preklican prek REST (status: cancelled) ali MCP (cancel_event) | bookingId, contactId, slotStart |
contact.created | kontakt ustvarjen prek REST ali MCP | contactId, firstName, lastName, email, phone |
task.created | naloga ustvarjena prek REST ali MCP | taskId, title, status, assigneeEmail, contactId, dueAt |
task.updated | naloga spremenjena prek REST ali MCP | ista polja kot task.created |
call.completed | zaključen telefonski klic AI agenta (dohodni) ali člana ekipe prek spletnega telefona (direction pove smer); pošlje se, ko je pogovor shranjen | conversationId, externalId, channel (phone), direction, callerNumber, contactId, bookingId, durationSeconds, summary |
Dogodke terminov, kontaktov in nalog sprožajo poti integracij (REST in MCP), ne dejanja vaše ekipe v aplikaciji — termin, ki ga član vpiše v koledar, webhooka ne pošlje. Izjema je call.completed, ki ga pošlje vsak zaključen telefonski klic.
POST /webhook HTTP/1.1
Content-Type: application/json
X-Kolio-Event: booking.created
X-Kolio-Timestamp: 2026-09-15T08:14:22.318Z
X-Kolio-Signature: sha256=3f1a9c…
{
"event": "booking.created",
"tenantId": "…",
"timestamp": "2026-09-15T08:14:22.318Z",
"data": {
"bookingId": "…",
"contactId": "…",
"serviceId": "…",
"slotStart": "2026-09-22T07:00:00.000Z",
"slotEnd": "2026-09-22T07:30:00.000Z",
"status": "confirmed"
}
}X-Kolio-Event nosi ime dogodka, X-Kolio-Timestamp čas dogodka (enak polju timestamp), X-Kolio-Signature podpis.import { createHmac, timingSafeEqual } from "node:crypto";
function verifyKolioSignature(rawBody, signatureHeader, secret) {
const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader ?? "");
return a.length === b.length && timingSafeEqual(a, b);
}Omejitve in dobra praksa
Kolio REST API v1 nima idempotenčnega ključa in nima ponovnih poskusov webhookov, zato mora integracija sama preprečevati podvojene zapise — s preverjanjem obstoja pred ustvarjanjem in s shranjevanjem id-jev, ki jih Kolio vrne.
| Kaj | Vrednost |
|---|---|
| Največ zapisov v seznamu | limit privzeto 50, največ 200; stranjenja (cursor/offset) ni — ožite z from/to ali filtri |
| Časovna omejitev webhooka | 10 s na zahtevo, en poskus |
| Idempotenca | ni podprta — ponovljen POST ustvari nov zapis (termin le, če je prostor) |
| Priloge | prek API-ja ni mogoče nalagati; časovnica naloge vrne le metapodatke prilog in pot za prenos, ki zahteva sejo člana |
| Obsegi ključa | določeni ob ustvarjanju; sprememba = nov ključ |
| Revizijska sled | vsaka sprememba naloge in vsaka opomba kontakta prek API-ja nosi avtorja api: + ime ključa |
- Za vsako integracijo uporabite ločen ključ z lastnim imenom — v časovnici boste videli, katera integracija je posegla, in jo lahko preklicali, ne da bi ustavili druge.
- Pred
POST /contactspoiščite kontakt poemail,phonealiexternalId; predPOST /bookingspreberite zasedenost obdobja in pri več lokacijah podajtelocationId. - Za preklic termina uporabite
PATCH { "status": "cancelled" }, za konec nalogePATCH { "status": "arhivirana" };DELETEje trajen in briše tudi časovnico. - Pošiljajte čase z odmikom in shranjujte id-je iz odgovorov (
data.id) — to je edini zanesljiv ključ za kasnejši PATCH. - Napake obravnavajte po polju
error, ne po besedilumessage, ki je namenjeno ljudem in se lahko spremeni.
