Webhooky a API
Napojte obchod klienta na ERP, externý sklad alebo Zapier. API kľúč dá cudziemu systému presne vymedzený prístup do Admin API a webhook mu pri udalosti v obchode pošle podpísanú správu.
API kľúč
- Kľúč založí obsluha obchodu v administrácii v časti Obchod › Integrácie, vyberie mu rozsahy a skopíruje ho. Ukáže sa len raz, v databáze je len jeho hash. Zrušený kľúč prestane platiť pri ďalšej požiadavke.
- Kľúč patrí jednému trhu obchodu. Požiadavka ide na Admin API (GraphQL, POST /admin-api) s kľúčom v hlavičke
vendure-api-keya s tokenom trhu v hlavičkevendure-token; adresu aj token ukáže tá istá obrazovka. Bez tokenu trhu kľúč neplatí. - Kľúč smie len operácie svojich rozsahov z tabuľky nižšie a dotaz
activeChannel; každá iná vráti FORBIDDEN. Platby, vrátenie peňazí, zrušenie objednávky, nastavenia ani práva nedovolí žiadny rozsah. - Kľúč má strop 300 požiadaviek za minútu. Nad ním príde odpoveď 429 s hlavičkou Retry-After.
curl https://admin.portican.com/admin-api \
-H 'content-type: application/json' \
-H 'vendure-api-key: <API key>' \
-H 'vendure-token: <market token>' \
-d '{"query":"{ orders(options: { take: 5 }) { items { code state totalWithTax } } }"}'
Rozsahy kľúča
Z kódu platformy. Tento zoznam sa skladá priamo zo zdrojového kódu platformy a každé nasadenie overí, že s ním sedí.
| Rozsah | Čo smie |
|---|---|
Čítanie objednávokobjednavky-citanie | Objednávky s položkami a sumami vrátane údajov zákazníka v nich (meno, adresa doručenia).order, orders |
Expedíciaexpedicia | Čítanie objednávok, založenie zásielky a zmena jej stavu. Sledovacie číslo do zásielky zapisuje štítok, ktorý tlačí obsluha, nie kľúč.order, orders, fulfillmentHandlers, addFulfillmentToOrder, transitionFulfillmentToState |
Čítanie katalógukatalog-citanie | Produkty, varianty so skladom, kategórie a filtre.product, products, productVariant, productVariants, collection, collections, facet, facets |
Úprava katalógukatalog-zapis | Zmena produktov a variantov vrátane ceny a skladu, bez mazania.product, products, productVariant, productVariants, collection, collections, facet, facets, updateProduct, updateProductVariants |
Čítanie zákazníkovzakaznici-citanie | Zákazníci s kontaktmi a adresami.customer, customers |
Webhooky
- Webhook pridá obsluha v tej istej obrazovke: adresu a udalosti. Adresa musí byť https na verejnom serveri na štandardnom porte, bez mena a hesla; adresa do vnútornej siete sa neuloží. Trh má najviac 10 webhookov.
- Každá správa je POST s telom JSON a hlavičkami
portican-podpis,portican-udalost,portican-id-udalosti,portican-pokus. Tlačidlo Poslať skúšobnú udalosť pošle udalosťskuska. - Správa nesie identifikátory, stav, sumy a položky, nikdy meno, e-mail, telefón ani adresu zákazníka. Podrobnosti si systém prečíta API kľúčom s rozsahom, ktorý mu obchodník dal.
Udalosti
Z kódu platformy. Tento zoznam sa skladá priamo zo zdrojového kódu platformy a každé nasadenie overí, že s ním sedí.
| Udalosť | Kedy príde |
|---|---|
objednavka.prijata | Zákazník dokončil objednávku (aj pri platbe prevodom alebo na dobierku). |
objednavka.zaplatena | Objednávka je zaplatená celá: platba kartou, prevod označený ako prijatý alebo dobierka po doručení. |
objednavka.odoslana | Zásielka odišla, celá objednávka alebo jej časť (pole stav). |
objednavka.dorucena | Zásielka je doručená, celá objednávka alebo jej časť (pole stav). |
objednavka.zrusena | Prijatá objednávka je zrušená. |
zasoba.zmenena | Zmenil sa sklad alebo rezervované kusy variantu: naskladnenie, predaj, rezervácia v objednávke, zrušenie. |
zakaznik.novy | V obchode pribudol zákazník: registrácia alebo prvý nákup bez účtu. |
Telo správy
Pole id je rovnaké ako hlavička portican-id-udalosti a pri každom pokuse rovnaké. Sumy sú v najmenšej jednotke meny (centoch). Verzia tvaru je 1; polia môžu pribúdať, existujúce sa nemenia.
{
"id": "ud_3f9a2c7e1b5d4e8f9a0b1c2d3e4f5a6b",
"udalost": "objednavka.zaplatena",
"verzia": 1,
"obchod": "sk",
"vytvorena": "2026-10-20T10:15:00.000Z",
"data": {
"objednavka": {
"id": "1042",
"kod": "R3K9QZ",
"stav": "PaymentSettled",
"mena": "EUR",
"sumaSDph": 4890,
"sumaBezDph": 3976,
"polozky": [
{
"sku": "KV-ROZA-50",
"mnozstvo": 2,
"cenaZaKusSDph": 1995
}
],
"prijata": "2026-10-20T10:12:41.000Z"
}
}
}
Podpis
- Hlavička
portican-podpismá tvar t=čas,v1=podpis, ako pri Stripe. Podpis je HMAC-SHA256 tajomstvom webhooku nad textom čas, bodka a surové telo správy, zapísaný šestnástkovo. - Tajomstvo sa ukáže raz pri pridaní webhooku a pri výmene; výmena staré tajomstvo hneď zruší.
- Overujte surové telo presne tak, ako prišlo, pred rozobraním JSON. Správu s časom starším než 300 sekúnd odmietnite; pri každom pokuse je čas nový.
import { createHmac, timingSafeEqual } from 'node:crypto';
// rawBody: request body exactly as received, before JSON.parse
function verifySignature(rawBody, header, secret, toleranceSeconds = 300) {
// header = request.headers['portican-podpis'], e.g. "t=1792500000,v1=5f2c..."
const parts = Object.fromEntries(header.split(',').map(p => p.split('=')));
const t = Number(parts.t);
if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSeconds) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
const received = String(parts.v1 ?? '');
return expected.length === received.length && timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}
Doručenie a opakovanie
- Doručená je správa, na ktorú príde odpoveď 2xx do 10 sekúnd. Odpovedzte hneď a spracujte ju neskôr. Presmerovanie sa nesleduje a ráta sa ako zlyhanie.
- Po zlyhaní príde ďalší pokus po 1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h. Kým adresa zlyháva, chodí na ňu jeden pokus naraz a ostatné správy počkajú; prvá úspešná odpoveď pošle aj ich.
- Po 8 neúspešných pokusoch za sebou (asi dva dni) sa webhook vypne a obchod dostane e-mail. Po zapnutí sa nedoručené správy dajú poslať znova z denníka doručení.
- Poradie správ nie je zaručené a tá istá správa môže prísť dvakrát. Rozhoduje čas vytvorena v tele a id udalosti: druhú správu s tým istým id zahoďte.
- Denník doručení s kódom odpovede vidí obsluha na obrazovke Integrácie 30 dní.