Skip to main content
Navodila za uporabo programa Quibi
Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Toggle Dark/Light/Auto mode Back to homepage

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).

Pogoji

  • 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.

Nastavitev

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.

Zahtevek

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
  }
}

Polja

PoljePomen
idEnolič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_idID podjetja v Quibiju.
item_id, skuID in šifra artikla.
unitEnota mere artikla (npr. kos, kg). Količine so v tej enoti.
is_kitKosovnica (sestavljen artikel). Njena zaloga je število kompletov, ki jih je mogoče sestaviti iz sestavin.
scopeZa 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_handZaloga na skladišču na današnji dan.
quantity_reservedRezervirano z odprtimi naročili kupcev v zadnjih 7 dneh, ki še nimajo dobavnice ali računa.
quantity_availablequantity_on_hand - quantity_reserved.
quantity_type, quantityKoličina, ki ste jo izbrali v nastavitvah (available ali on_hand).
stock_versionRazlič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).

Testni dogodek

{ "id": "evt_test_...", "type": "webhook.test", "schema_version": 1, "test": true,
  "occurred_at": "...", "company_id": 123, "data": { "subscription_id": 7, "message": "..." } }

Preverjanje podpisa

signed_message = X-Quibi-Timestamp + "." + surovo_telo_zahtevka
podpis = hex(HMAC-SHA256(skrivnost, signed_message))
X-Quibi-Signature: v1=<podpis>

Kako preverite podpis:

  1. Podpis izračunajte nad surovimi bajti telesa, preden JSON razčlenite.
  2. Podpis primerjajte s primerjavo v konstantnem času.
  3. Zavrnite zahtevke s časovnim žigom, starejšim od 5 minut.
  4. 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

Podvojitve in vrstni red

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.

  1. Shranjujte že obdelane id in podvojenega potrdite z 2xx, ne da bi ga obdelali še enkrat.
  2. Za vsak par artikel + obseg (item_id + scope) hranite zadnjo obdelano stock_version. Dogodek z enako ali nižjo različico prezrite, saj imate novejše stanje.
  3. Oboje zapišite v isti transakciji kot novo stanje zaloge.

Odziv in ponovitve

  • Odgovorite v 10 sekundah z 2xx. Dogodek shranite in ga obdelajte asinhrono. Quibi čaka največ 15 s, odgovor pa prebere le do 64 KB.
  • 2xx pomeni uspeh.
  • Omrežno napako, časovno prekoračitev, 408, 429 in 5xx Quibi ponovi s stopnjevanim odmikom: 30 s, 1 min, 2 min, … do 1 ure, približno 24 ur oziroma 30 poskusov. Glavo Retry-After upošteva do 1 ure.
  • Druge 4xx in 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.

Začetni prenos in uskladitev

Nova naročnina prejema le prihodnje spremembe. Trenutno stanje dobite takole:

  1. Ustvarite webhook in začnite sprejemati dogodke.

  2. Preberite trenutno stanje po straneh:

    GET /api2/webhooki/zaloga/ID_WEBHOOKA?po=0&limit=500
    

    Prijava 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 je next_cursor null, ste na koncu.

  3. 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, ima stock_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.

Znane omejitve

  • 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č.