Webhooky a API
Napojte obchod klienta na ERP, externí sklad nebo Zapier. API klíč dá cizímu systému přesně vymezený přístup do Admin API a webhook mu při události v obchodě pošle podepsanou zprávu.
API klíč
- Klíč založí obsluha obchodu v administraci v části Obchod › Integrace, vybere mu rozsahy a zkopíruje ho. Zobrazí se jen jednou, v databázi je jen jeho hash. Zrušený klíč přestane platit při dalším požadavku.
- Klíč patří jednomu trhu obchodu. Požadavek jde na Admin API (GraphQL, POST /admin-api) s klíčem v hlavičce
vendure-api-keya s tokenem trhu v hlavičcevendure-token; adresu i token ukáže stejná obrazovka. Bez tokenu trhu klíč neplatí. - Klíč smí jen operace svých rozsahů z tabulky níže a dotaz
activeChannel; každá jiná vrátí FORBIDDEN. Platby, vrácení peněz, zrušení objednávky, nastavení ani práva nedovolí žádný rozsah. - Klíč má strop 300 požadavků za minutu. Nad ním přijde odpověď 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 klíče
Z kódu platformy. Tento seznam se skládá přímo ze zdrojového kódu platformy a každé nasazení ověří, že s ním souhlasí.
| Rozsah | Co smí |
|---|---|
Čtení objednávekobjednavky-citanie | Objednávky s položkami a částkami včetně údajů zákazníka v nich (jméno, doručovací adresa).order, orders |
Expediceexpedicia | Čtení objednávek, založení zásilky a změna jejího stavu. Sledovací číslo do zásilky zapisuje štítek, který tiskne obsluha, ne klíč.order, orders, fulfillmentHandlers, addFulfillmentToOrder, transitionFulfillmentToState |
Čtení katalogukatalog-citanie | Produkty, varianty se skladem, kategorie a filtry.product, products, productVariant, productVariants, collection, collections, facet, facets |
Úprava katalogukatalog-zapis | Změna produktů a variant včetně ceny a skladu, bez mazání.product, products, productVariant, productVariants, collection, collections, facet, facets, updateProduct, updateProductVariants |
Čtení zákazníkůzakaznici-citanie | Zákazníci s kontakty a adresami.customer, customers |
Webhooky
- Webhook přidá obsluha na stejné obrazovce: adresu a události. Adresa musí být https na veřejném serveru se standardním portem, bez jména a hesla; adresa do vnitřní sítě se neuloží. Trh má nejvýše 10 webhooků.
- Každá zpráva je POST s tělem JSON a hlavičkami
portican-podpis,portican-udalost,portican-id-udalosti,portican-pokus. Tlačítko Poslat zkušební událost pošle událostskuska. - Zpráva nese identifikátory, stav, částky a položky, nikdy jméno, e-mail, telefon ani adresu zákazníka. Podrobnosti si systém přečte API klíčem s rozsahem, který mu obchodník dal.
Události
Z kódu platformy. Tento seznam se skládá přímo ze zdrojového kódu platformy a každé nasazení ověří, že s ním souhlasí.
| Událost | Kdy přijde |
|---|---|
objednavka.prijata | Zákazník dokončil objednávku (i při platbě převodem nebo na dobírku). |
objednavka.zaplatena | Objednávka je zaplacená celá: platba kartou, převod označený jako přijatý nebo dobírka po doručení. |
objednavka.odoslana | Zásilka odešla, celá objednávka nebo její část (pole stav). |
objednavka.dorucena | Zásilka je doručená, celá objednávka nebo její část (pole stav). |
objednavka.zrusena | Přijatá objednávka je zrušená. |
zasoba.zmenena | Změnil se sklad nebo rezervované kusy varianty: naskladnění, prodej, rezervace v objednávce, zrušení. |
zakaznik.novy | V obchodě přibyl zákazník: registrace nebo první nákup bez účtu. |
Tělo zprávy
Pole id je stejné jako hlavička portican-id-udalosti a při každém pokusu stejné. Částky jsou v nejmenší jednotce měny (centech). Verze tvaru je 1; pole mohou přibývat, stávající se nemění.
{
"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, jako u Stripe. Podpis je HMAC-SHA256 tajemstvím webhooku nad textem čas, tečka a surové tělo zprávy, zapsaný šestnáctkově. - Tajemství se zobrazí jednou při přidání webhooku a při výměně; výměna staré tajemství hned zruší.
- Ověřujte surové tělo přesně tak, jak přišlo, před rozebráním JSON. Zprávu s časem starším než 300 sekund odmítněte; při každém pokusu 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čení a opakování
- Doručená je zpráva, na kterou přijde odpověď 2xx do 10 sekund. Odpovězte hned a zpracujte ji později. Přesměrování se nesleduje a počítá se jako selhání.
- Po selhání přijde další pokus po 1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h. Dokud adresa selhává, chodí na ni jeden pokus najednou a ostatní zprávy počkají; první úspěšná odpověď pošle i je.
- Po 8 neúspěšných pokusech za sebou (zhruba dva dny) se webhook vypne a obchod dostane e-mail. Po zapnutí lze nedoručené zprávy poslat znovu z deníku doručení.
- Pořadí zpráv není zaručené a stejná zpráva může přijít dvakrát. Rozhoduje čas vytvorena v těle a id události: druhou zprávu se stejným id zahoďte.
- Deník doručení s kódem odpovědi vidí obsluha na obrazovce Integrace 30 dní.