Webhooki
Webhooki vašemu sistemu sporočijo spremembo v Quibiju takoj, ko se zgodi. Pri tem vam ni treba stalno klicati API-ja. Quibi ob spremembi pošlje podpisan zahtevek POST na vaš HTTPS naslov.
Prvi podprt dogodek je sprememba zaloge (inventory.stock_changed).
- Aktivna naročnina na Quibi. Ko naročnina poteče, se dogodki ne pošiljajo. Po podaljšanju Quibi pošlje stanja, ki so se medtem spremenila.
- Paket z zunanjim API-jem.
- Uporabnik s pravico Nastavitve → Zunanje povezave.
V Nastavitve → Zunanje povezave → Webhooki kliknite Dodaj in vnesite:
- URL naslov. Naslov mora biti
https://, na vratih 443 in javno dosegljiv. Quibi zavrne lokalne, zasebne in rezervirane naslove ter ne sledi preusmeritvam. - Skladišča in obseg:
- Vsako skladišče posebej: za vsako izbrano skladišče pride ločen dogodek.
- Seštevek izbranih skladišč: pride en dogodek s skupno količino vseh izbranih skladišč.
- Poslano količino (polje
quantity): razpoložljiva zaloga ali zaloga na skladišču.
Ob shranjevanju Quibi enkrat prikaže skrivnost za preverjanje podpisa (whsec_...). Shranite jo varno. Novo skrivnost ustvarite z gumbom Nova skrivnost; stara takoj preneha veljati.
Z gumbom Testna dostava pošljete testni dogodek webhook.test. Testni dogodek ne spremeni zaloge.
POST https://vas-sistem.si/quibi-webhook
Content-Type: application/json
User-Agent: Quibi-Webhooks/1
X-Quibi-Event-Id: evt_6f1c0b2a9d4e8f7a6b5c4d3e
X-Quibi-Timestamp: 1792570530
X-Quibi-Signature: v1=5d41402abc4b2a76b9719d911017c592...
{
"id": "evt_6f1c0b2a9d4e8f7a6b5c4d3e",
"type": "inventory.stock_changed",
"schema_version": 1,
"occurred_at": "2026-10-21T08:15:30Z",
"company_id": 123,
"data": {
"item_id": 456,
"sku": "ART-001",
"unit": "kos",
"is_kit": false,
"scope": { "type": "warehouse", "warehouse_id": 2 },
"quantity_on_hand": "12.000",
"quantity_reserved": "3.000",
"quantity_available": "9.000",
"quantity_type": "available",
"quantity": "9.000",
"stock_version": 1842
}
}
| Polje | Pomen |
|---|---|
id | Enolični ID dogodka. Ponovitve istega dogodka imajo isti ID in enako telo. |
occurred_at | Čas posnetka stanja (UTC). Za vrstni red ga ne uporabljajte, uporabite stock_version. |
company_id | ID podjetja v Quibiju. |
item_id, sku | ID in šifra artikla. |
unit | Enota mere artikla (npr. kos, kg). Količine so v tej enoti. |
is_kit | Kosovnica (sestavljen artikel). Njena zaloga je število kompletov, ki jih je mogoče sestaviti iz sestavin. |
scope | Za katero zalogo gre: {"type":"warehouse","warehouse_id":2} za eno skladišče ali {"type":"aggregate","warehouse_ids":[2,3]} za seštevek. Seštevek ni skladišče. |
quantity_on_hand | Zaloga na skladišču na današnji dan. |
quantity_reserved | Rezervirano z odprtimi naročili kupcev v zadnjih 7 dneh, ki še nimajo dobavnice ali računa. |
quantity_available | quantity_on_hand - quantity_reserved. |
quantity_type, quantity | Količina, ki ste jo izbrali v nastavitvah (available ali on_hand). |
stock_version | Različica stanja za ta artikel in ta obseg. Narašča, ni pa nujno zaporedna. |
- Količine so decimalni nizi z najmanj tremi decimalnimi mesti in brez izgube natančnosti. Ne pretvarjajte jih v
float. - Zaloga je lahko negativna. Quibi je ne omeji na nič; odločitev, kaj z negativno zalogo, je vaša.
- Vedno se pošlje absolutno stanje, nikoli razlika (
+5/-2).
{ "id": "evt_test_...", "type": "webhook.test", "schema_version": 1, "test": true,
"occurred_at": "...", "company_id": 123, "data": { "subscription_id": 7, "message": "..." } }
signed_message = X-Quibi-Timestamp + "." + surovo_telo_zahtevka
podpis = hex(HMAC-SHA256(skrivnost, signed_message))
X-Quibi-Signature: v1=<podpis>
Kako preverite podpis:
- Podpis izračunajte nad surovimi bajti telesa, preden JSON razčlenite.
- Podpis primerjajte s primerjavo v konstantnem času.
- Zavrnite zahtevke s časovnim žigom, starejšim od 5 minut.
- Glava lahko vsebuje več podpisov, ločenih z vejico. Zahtevek je veljaven, če se ujema vsaj eden.
Vsak poskus ima svež časovni žig in nov podpis, telo pa ostane enako.
PHP:
$telo = file_get_contents('php://input');
$ts = $_SERVER['HTTP_X_QUIBI_TIMESTAMP'] ?? '';
$podpis = $_SERVER['HTTP_X_QUIBI_SIGNATURE'] ?? '';
if (!ctype_digit($ts) || abs(time() - (int)$ts) > 300) {
http_response_code(400); exit;
}
$pricakovan = 'v1=' . hash_hmac('sha256', $ts . '.' . $telo, getenv('QUIBI_WEBHOOK_SECRET'));
$ok = false;
foreach (explode(',', $podpis) as $p) {
$ok = $ok || hash_equals($pricakovan, trim($p));
}
if (!$ok) {
http_response_code(401); exit;
}
$dogodek = json_decode($telo, true);
Node.js (Express):
const crypto = require('crypto');
app.post('/quibi-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const ts = req.get('X-Quibi-Timestamp') || '';
if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return res.sendStatus(400);
const pricakovan = 'v1=' + crypto.createHmac('sha256', process.env.QUIBI_WEBHOOK_SECRET)
.update(ts + '.').update(req.body).digest('hex');
const ok = (req.get('X-Quibi-Signature') || '').split(',').some(p => {
const a = Buffer.from(p.trim()), b = Buffer.from(pricakovan);
return a.length === b.length && crypto.timingSafeEqual(a, b);
});
if (!ok) return res.sendStatus(401);
const dogodek = JSON.parse(req.body);
res.sendStatus(200);
});
Python (Flask):
import hmac, hashlib, os, time
from flask import request, abort
@app.post("/quibi-webhook")
def quibi_webhook():
telo = request.get_data()
ts = request.headers.get("X-Quibi-Timestamp", "")
if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
abort(400)
pricakovan = "v1=" + hmac.new(os.environ["QUIBI_WEBHOOK_SECRET"].encode(),
ts.encode() + b"." + telo, hashlib.sha256).hexdigest()
if not any(hmac.compare_digest(pricakovan, p.strip())
for p in request.headers.get("X-Quibi-Signature", "").split(",")):
abort(401)
dogodek = request.get_json()
return "", 200
Quibi zagotavlja dostavo vsaj enkrat. Isti dogodek lahko pride večkrat (npr. če vaš odziv ne pride do nas), dogodki pa lahko pridejo v drugačnem vrstnem redu, kot so nastali.
- Shranjujte že obdelane
idin podvojenega potrdite z2xx, ne da bi ga obdelali še enkrat. - Za vsak par artikel + obseg (
item_id+scope) hranite zadnjo obdelanostock_version. Dogodek z enako ali nižjo različico prezrite, saj imate novejše stanje. - Oboje zapišite v isti transakciji kot novo stanje zaloge.
- Odgovorite v 10 sekundah z
2xx. Dogodek shranite in ga obdelajte asinhrono. Quibi čaka največ 15 s, odgovor pa prebere le do 64 KB. 2xxpomeni uspeh.- Omrežno napako, časovno prekoračitev,
408,429in5xxQuibi ponovi s stopnjevanim odmikom: 30 s, 1 min, 2 min, … do 1 ure, približno 24 ur oziroma 30 poskusov. GlavoRetry-Afterupošteva do 1 ure. - Druge
4xxin preusmeritve (3xx) so dokončna napaka. Po odpravi vzroka jih lahko ročno ponovite v Webhooki → Dostave → Ponovi. - Dostave enemu prejemniku tečejo zaporedno, zato počasen prejemnik zadrži le sebe.
- Če se nastavitve spremenijo (URL, skladišča, obseg, vrsta količine ali skrivnost), se še čakajoče dostave prekličejo in ne odidejo na nov naslov. Celotno stanje nato pošljete z gumbom Pošlji celotno stanje.
Nova naročnina prejema le prihodnje spremembe. Trenutno stanje dobite takole:
Ustvarite webhook in začnite sprejemati dogodke.
Preberite trenutno stanje po straneh:
GET /api2/webhooki/zaloga/ID_WEBHOOKA?po=0&limit=500Prijava je enaka kot pri ostalem API-ju. Odgovor:
{ "error": false, "message": "", "data": { "subscription_id": 7, "schema_version": 1, "next_cursor": 98123, "scopes": [ { "scope": {"type":"warehouse","warehouse_id":2}, "items": [ { "item_id": 456, "sku": "ART-001", "quantity": "9.000", "stock_version": 1842, "...": "..." } ] } ] } }Naslednjo stran preberete z
po=next_cursor; ko jenext_cursornull, ste na koncu.Za vsak artikel in obseg obdržite stanje z višjo
stock_version, bodisi iz odgovora bodisi iz dogodka. Artikel, ki še ni imel nobenega dogodka, imastock_version: 0.
Odgovor ni atomaren posnetek vseh artiklov hkrati. Ker vsaka sprememba po branju pride kot dogodek z višjo različico, se stanje na vaši strani vedno uskladi. Za kasnejše preverjanje razhajanj postopek ponovite ali v Quibiju kliknite Pošlji celotno stanje.
- Rezervacija naročila preneha po 7 dneh. Quibi to zazna z nočno uskladitvijo, zato lahko pride do 24 ur pozneje.
- Enako velja za dokumente z datumom v prihodnosti: vplivajo na zalogo šele na ta dan, dogodek pa pride ob nočni uskladitvi.
- Običajen zamik dogodka je nekaj sekund, pri večjih uvozih tudi več.