Webhookuri de ieșire
Verificat
Pe scurt
Secțiune intitulată „Pe scurt”Webhookul este opusul REST și MCP: nu întrebați dumneavoastră, se anunță MitoOps. Când în cont apare un eveniment la care sunteți abonat, trimitem la adresa dumneavoastră un POST cu un plic scurt, semnat. Plicul poartă identificatori și stări, nu conținutul comenzii: detaliul îl încarcă sistemul dumneavoastră prin interfața REST, cu propria cheie.
Abonamentele le gestionați în aplicație: Setări → API & MCP → Webhookuri de ieșire. Sunt disponibile de la tariful Start; este necesar dreptul Webhookuri de ieșire (citire sau gestionare).
Abonamentul (endpoint)
Secțiune intitulată „Abonamentul (endpoint)”Endpointul are un nume, o adresă, o listă de evenimente și un domeniu de magazine online. La creare primiți un secret: se afișează o singură dată, apoi niciodată; îl puteți înlocui oricând (rotire), iar cel vechi încetează imediat să fie valabil.
- Adresa trebuie să fie publică și prin
https://, pe portul standard. Adresele către rețeaua internă (mașina locală, intervale private, metadatele cloudului, intervale VPN) se refuză la salvare și la fiecare livrare: numele se rezolvă din nou, iar conexiunea se leagă de adresele verificate. - Redirecționările nu sunt urmate. Un răspuns
3xxeste un eșec. - Magazine online: toate (inclusiv cele care se vor adăuga) sau cele alese. Un eveniment dintr-un magazin online în afara domeniului nu se trimite.
- Livrarea de test, din buton, trimite evenimentul
pingpe aceeași cale ca unul real, inclusiv semnătura și înregistrarea în jurnal. - Endpointul poate fi dezactivat (livrările în așteptare se sar) și șters (jurnalul rămâne).
Evenimente
Secțiune intitulată „Evenimente”| Eveniment | Când | resource.type |
Câmpuri în data |
|---|---|---|---|
order.created |
comandă nouă din magazinul online | order |
order_code |
order.paid |
comandă marcată ca plătită | order |
order_code |
order.status_changed |
schimbarea stării comenzii | order |
order_code, status_id, previous_status_id |
shipment.created |
expediere creată la curier | shipment |
shipment_id, order_code, carrier_code, tracking_number |
shipment.status_changed |
schimbarea stării expedierii (curier sau operator) | shipment |
shipment_id, order_code, carrier_code, status, previous_status, tracking_number |
shipment.delivered |
expediere livrată; în plus față de shipment.status_changed |
shipment |
ca mai sus, status este DELIVERED |
inventory.stock_changed |
mișcarea stocului unui articol | inventory_item |
item_id, sku, kind |
invoice.created |
factură emisă | invoice |
invoice_code, order_code |
claim.created |
reclamație deschisă (de client sau de operator) | claim |
claim_code, order_code |
claim.status_changed |
schimbarea stării reclamației | claim |
claim_code, order_code, status_id |
claim.closed |
reclamație închisă | claim |
claim_code, order_code |
search_console.connection.changed |
starea conexiunii Search Console s-a schimbat (conectare, schimbare site, acces pierdut, deconectare) | search_console_property |
market, status, previous_status, property, previous_property, changed_at |
search_console.sync.completed |
sincronizarea arhivei a adăugat sau a modificat zile | search_console_property |
market, property, search_types, data_state, final_data_through, fresh_data_through, days_upserted, revised_dates, sync_version, synced_at |
search_console.sync.failed |
sincronizarea arhivei a eșuat | search_console_property |
market, property, error, error_code, last_successful_sync_at, retry_at |
product_content.changed |
MitoOps a scris în magazin o descriere, o descriere scurtă sau un text SEO al produsului modificate | product |
store_id, market, entity, entity_id, canonical_url, source, source_run_id, changed_fields, before_hash, after_hash, changed_at |
category_content.changed |
MitoOps a scris în magazin o descriere de sus sau de jos ori un text SEO al categoriei modificate | category |
ca la product_content.changed |
ping |
livrare de test din buton | webhook_endpoint |
message, endpoint |
Evenimentele provin din același strat comercial ca automatizările: ce pornește o automatizare poate fi urmărit și printr-un webhook. Coletele retur nu se trimit ca shipment.*: aparțin reclamației.
Modificarea textelor produselor și categoriilor
Secțiune intitulată „Modificarea textelor produselor și categoriilor”product_content.changed și category_content.changed apar o singură dată pe scriere și magazin, când MitoOps scrie în magazin un text care s-a schimbat cu adevărat — din fișa produsului, editarea în masă, import, ecranul categoriilor, dintr-o propunere aprobată sau dintr-o scriere autonomă. Modificarea prețului, a stocului sau a codului, ori salvarea din nou a aceluiași text nu declanșează evenimentul. Modificările făcute direct în administrarea magazinului nu sunt raportate de acest eveniment.
entityesteproductsaucategory;entity_id(șiresource.id) este codul produsului, respectiv ID-ul categoriei în magazin — aceleași cu care citiți textele prinproducts_content_getșicategories_content_get.store_ideste codul magazinului, același castore.source:ui(o persoană în aplicație),assistant(asistentul din aplicație),mcp(o propunere prin MCP aprobată de o persoană),autonomous(o propunere scrisă în regim autonom). Valoarearesteste rezervată — REST este astăzi doar pentru citire.source_run_id: ID-ul propunerii la scrierile aprobate și autonome; la celelalte scrieri ale produsului, ID-ul lotului de scriere (Modificări produse); la o categorie salvată în afara unei propuneri,null.changed_fieldsenumeră câmpurile modificate: la produsdescription,shortDescription,metaTitle,metaDescription, la categoriedescription,descriptionBottom,metaTitle,metaDescription.before_hashșiafter_hashconțin pentru fiecare SHA-256 al textului în UTF-8 (o valoare lipsă = amprenta șirului gol) — aceeași valoare pe care o întoarce câmpulhashla citire. Plicul nu conține textul propriu-zis.- După aprobarea unei propuneri,
after_hasheste amprenta a ceea ce magazinul a salvat efectiv (WordPress elimină, de exemplu, un bloc<style>), nu a ceea ce s-a propus. canonical_urleste adresa publică a produsului sau a categoriei, dacă MitoOps o cunoaște; altfelnull.
Ce poate citi și propune cheia dumneavoastră pe un anumit magazin și dacă o propunere se va scrie singură aflați dinainte din politica de conținut: GET /api/v1/product-content/policy?market=… sau instrumentul MCP products_content_policy (domeniul product-content:read).
Fiecare livrare este un JSON cu versiunea plicului. Un câmp nou poate apărea fără schimbarea versiunii; o schimbare a semnificației unui câmp înseamnă o versiune nouă.
{ "event_id": "9b2f0c1e-6d3a-4c7e-9a2b-0f1e2d3c4b5a", "event_type": "shipment.delivered", "version": 1, "occurred_at": "2026-09-03T08:41:12.318Z", "tenant": "00001", "store": "sk", "resource": { "type": "shipment", "id": "5521" }, "data": { "shipment_id": "5521", "order_code": "2026001234", "carrier_code": "gls", "status": "DELIVERED", "previous_status": "IN_TRANSIT", "tracking_number": "GLS123456789" }}event_ideste unic pentru eveniment. Dacă același eveniment este urmărit de două endpointuri ale dumneavoastră, ele primesc același ID. O încercare repetată poartă același ID și același corp.storeeste codul magazinului online (market), același pe care îl folosește REST.tenanteste identificatorul contului dumneavoastră în MitoOps.
Antete și semnătură
Secțiune intitulată „Antete și semnătură”Content-Type: application/jsonUser-Agent: MitoOps-Webhooks/1X-MitoOps-Event: shipment.deliveredX-MitoOps-Event-Id: 9b2f0c1e-6d3a-4c7e-9a2b-0f1e2d3c4b5aX-MitoOps-Timestamp: 1756888872X-MitoOps-Signature: v1=3f1a…c9e0X-MitoOps-Delivery: 184Semnătura este HMAC-SHA256 cu cheia = secretul endpointului, peste șirul:
<X-MitoOps-Timestamp> + "." + <corpul exact al cererii>Rezultatul este hexazecimal și apare în antet cu prefixul de versiune v1=. Marcajul de timp este timpul unix în secunde.
Verificarea de partea dumneavoastră
Secțiune intitulată „Verificarea de partea dumneavoastră”Verificați pe corpul brut al cererii (octeții așa cum au sosit), nu pe un JSON serializat din nou: orice schimbare a unui spațiu sau a ordinii cheilor invalidează semnătura. Comparați în timp constant și refuzați mesajele mai vechi de 5 minute.
import { createHmac, timingSafeEqual } from 'node:crypto';
function overMitoOpsWebhook({ tajomstvo, hlavicky, suroveTelo, teraz = Math.floor(Date.now() / 1000) }) { const cas = Number(hlavicky['x-mitoops-timestamp']); if (!Number.isFinite(cas) || Math.abs(teraz - cas) > 300) return false; // marcaj vechi sau lipsă
const prijaty = String(hlavicky['x-mitoops-signature'] || '') .split(',').map((s) => s.trim()).find((s) => s.startsWith('v1=')); if (!prijaty) return false;
const ocakavany = createHmac('sha256', tajomstvo) .update(String(cas) + '.').update(suroveTelo).digest('hex'); const a = Buffer.from(prijaty.slice(3), 'hex'); const b = Buffer.from(ocakavany, 'hex'); return a.length === b.length && timingSafeEqual(a, b);}import hmac, hashlib, time
def over_mitoops_webhook(tajomstvo: str, hlavicky: dict, surove_telo: bytes) -> bool: try: cas = int(hlavicky["X-MitoOps-Timestamp"]) except (KeyError, ValueError): return False if abs(int(time.time()) - cas) > 300: return False podpis = next((s.strip() for s in hlavicky.get("X-MitoOps-Signature", "").split(",") if s.strip().startswith("v1=")), None) if not podpis: return False ocakavany = hmac.new(tajomstvo.encode(), f"{cas}.".encode() + surove_telo, hashlib.sha256).hexdigest() return hmac.compare_digest(podpis[3:], ocakavany)Protecție împotriva reluării
Secțiune intitulată „Protecție împotriva reluării”Semnătura acoperă marcajul de timp, deci un mesaj interceptat nu poate fi trimis mai târziu cu o oră nouă. Pe lângă verificarea timpului, păstrați event_id al ultimelor livrări și ignorați duplicatele: livrarea repetată este o proprietate a sistemului, nu o eroare.
Răspuns, repetare și jurnal
Secțiune intitulată „Răspuns, repetare și jurnal”- Răspundeți cu
2xxîn 10 secunde. Corpul răspunsului nu se citește. O procesare care durează mai mult puneți-o în fundal și răspundeți imediat. - Un alt răspuns (
4xx,5xx), depășirea timpului sau o eroare de conexiune = eșec și repetare la intervale de 1, 5, 15, 60 și 240 de minute; în total șase încercări. Apoi livrarea esteFAILEDși așteaptă o repetare manuală din jurnal. - Un răspuns
3xxși o adresă care a încetat să se rezolve în rețeaua publică sunt eșecuri fără repetare: nu se rezolvă singure. - Jurnalul livrărilor din aplicație arată pentru fiecare încercare starea, codul HTTP, ora, numărul de încercări și evenimentul. Corpul mesajului nu se afișează în jurnal.
| Stare | Semnificație |
|---|---|
PENDING |
așteaptă o încercare sau următoarea repetare |
SENT |
destinatarul a răspuns 2xx |
FAILED |
încercările s-au epuizat sau eroare permanentă; poate fi repetată manual |
SKIPPED |
între timp endpointul a fost dezactivat sau șters |
Securitate
Secțiune intitulată „Securitate”- Secretul se stochează criptat și nu se scrie niciodată în jurnale sau în jurnalul livrărilor. Se afișează o singură dată; rotirea funcționează chiar și atunci când tariful nu mai include webhookuri: este o operație de securitate.
- Fără date personale. Plicul poartă identificatori și stări. Numele, adresa sau e-mailul clientului nu se trimit; cine are nevoie de ele le citește prin REST, cu propriul domeniu și audit.
- Doar HTTPS, doar adrese publice, fără redirecționări. Verificarea la salvare și la fiecare livrare protejează împotriva direcționării în rețeaua internă și împotriva schimbării DNS.
- Abonamentul îl creează un om, nu o cheie. O cheie de acces la REST sau un consimțământ OAuth nu pot crea un abonament: citirea la cerere și un flux permanent de evenimente către exterior sunt două permisiuni diferite.
- Izolare. Abonamentele și jurnalul se află în spațiul contului dumneavoastră; domeniul magazinelor online se evaluează la fiecare eveniment.
| Tarif | Webhookuri de ieșire | Endpointuri |
|---|---|---|
| Versiune de probă | — | 0 |
| Începător | — | 0 |
| Start | da | 5 |
| Creștere | da | 20 |
| Pro | da | 50 |
| Personalizat | conform acordului | conform acordului |
Se numără endpointurile neșterse, atât activate, cât și dezactivate. Reducerea tarifului nu șterge endpointurile existente; unul nou nu se adaugă până când numărul nu scade sub limită, iar la un tarif fără webhookuri evenimentele încetează să fie trimise până când tariful revine.
Webhook dintr-o automatizare
Secțiune intitulată „Webhook dintr-o automatizare”Endpointul îl puteți folosi și ca pas Trimite webhook în Automatizări: mesajul pleacă abia după îndeplinirea condițiilor regulii, nu la fiecare eveniment. Pasul doar alege endpointul: adresa, secretul și domeniul magazinelor online rămân în registru.
Mesajul are tipul automation.action (nu poate fi urmărit direct) și același plic, aceeași semnătură, repetare și jurnal ca celelalte evenimente. În data poartă automation.workflow_id, automation.run_id, automation.node_id, automation.source_event (evenimentul care a trezit regula) și identificatorii comenzii, expedierii sau cazului de reclamație; resource este entitatea rulării. Detaliul îl încărcați prin API-ul REST.
Suspendarea automată
Secțiune intitulată „Suspendarea automată”Dacă destinatarul nu răspunde la 30 de încercări la rând sau endpointul are mai mult de 5 000 de livrări în așteptare, MitoOps suspendă endpointul și vă trimite o notificare. Livrările în așteptare rămân; după repararea destinatarului, activați endpointul, iar ele se recuperează. Jurnalul livrărilor se păstrează 30 de zile.