Prezentare generală
Primește evenimente TicketWave ca cereri HTTP semnate în propria ta aplicație.
Webhooks
Un webhook este o cerere HTTP pe care TicketWave ți-o trimite. Ori de câte ori se întâmplă ceva pe serverul tău — se deschide un tichet, un membru este adăugat pe lista neagră — TicketWave face un POST cu un corp JSON către un URL care îți aparține.
Aceasta este diferența față de Log Channels: log channels scriu un embed în Discord pentru ca oamenii să-l citească, iar webhooks trimit evenimentul brut direct către codul tău.
Webhooks sunt o funcționalitate premium. Fără premium, endpoint-urile nu pot fi create și nu sunt livrate evenimente.
Creează un Endpoint
Deschide pagina endpoint-urilor
Server dashboard → Webhooks → Endpoints.
Adaugă un endpoint
Apasă Add Endpoint și completează două câmpuri:
| Field | Description |
|---|---|
| Endpoint URL | URL-ul https:// care primește cererile |
| Event Types | Ce evenimente ar trebui să primească acest endpoint |
Un endpoint primește doar tipurile pe care le bifezi. Nu este permis să nu selectezi nimic — alege cel puțin unul.
Copiază secretul de semnare
TicketWave generează un secret de semnare (whsec_…) în momentul în care endpoint-ul este creat. Deschide lista de endpoint-uri, afișează-l cu iconița ochiului și copiază-l în configurația aplicației tale.
Tratează secretul ca pe o parolă. Oricine îl are poate falsifica cereri care trec verificarea semnăturii. Păstrează-l într-o variabilă de mediu, niciodată în repository-ul tău.
Trimite un eveniment de test
Folosește butonul Send test event (avionul de hârtie) de pe rândul endpoint-ului. Acesta livrează o cerere reală, complet semnată, cu "test": true în payload, astfel încât să poți confirma că receptorul tău funcționează înainte ca un tichet real să depindă de el.
Rezultatul apare în istoricul Webhooks la fel ca orice altă livrare.
Cerințe pentru Endpoint
| Requirement | Detail |
|---|---|
| Scheme | Doar https:// — http:// este respins |
| Host | Trebuie să poată fi rezolvat public. Adresele private, loopback, link-local și CGNAT sunt refuzate |
| Response | Orice status 2xx contează ca succes |
| Timeout | Ai 10 secunde pentru a răspunde |
| Redirects | Nu sunt urmărite. Un 3xx contează ca eșec |
| Limit | Până la 5 endpoint-uri per server |
Verificarea hostului are loc atât când salvezi endpoint-ul cât și înainte de fiecare livrare, așa că un domeniu care ulterior începe să se rezolve către o adresă internă nu mai primește livrări.
Cererea
Fiecare livrare este un POST cu un corp JSON.
Headers
| Header | Example | Meaning |
|---|---|---|
Content-Type | application/json | Întotdeauna JSON |
User-Agent | TicketWave-Webhooks/1.0.5 | Versiunea botului care l-a trimis |
X-TicketWave-Event | ticket.created | Tipul evenimentului |
X-TicketWave-Delivery | wh_3f2a… | Id unic pentru această livrare |
X-TicketWave-Timestamp | 1786224191 | Secunde Unix, parte din semnătură |
X-TicketWave-Signature | sha256=9f86d0… | HMAC-ul cererii |
Body
Fiecare payload folosește aceeași structură. Doar data diferă în funcție de tipul evenimentului:
{
"event": "ticket.created",
"timestamp": "2026-08-26T08:23:11.000Z",
"guild_id": "123456789012345678",
"data": {
"ticket_id": "ticket-1042",
"ticket_num_id": 1042,
"channel_id": "998877665544332211",
"category": "🤖 Support",
"user": { "id": "987654321098765432", "username": "Luna" },
"created_at": "2026-08-26T08:23:11.000Z"
}
}Vezi Event Reference pentru obiectul data al fiecărui tip.
Verificarea Semnăturii
Oricine îți descoperă URL-ul endpoint-ului îi poate trimite o cerere POST. Semnătura este modul în care deosebești o livrare reală TicketWave de una falsificată.
Verifică întotdeauna. Un endpoint neverificat care creează sau închide lucruri în sistemul tău este o ușă deschisă.
Cum este construită semnătura
TicketWave unește timestamp-ul și corpul raw al cererii cu un punct și rulează HMAC-SHA256 peste rezultat folosind secretul endpoint-ului tău:
signed_payload = X-TicketWave-Timestamp + "." + raw_request_body
signature = HMAC_SHA256(signed_payload, your_endpoint_secret)Header-ul conține acel digest codificat hex și prefixat: sha256=<digest>.
Ce trebuie să facă receptorul tău
Citește corpul raw. Verifică-l împotriva exact așa cum l-ai primit. Dacă framework-ul tău parsează mai întâi JSON-ul și apoi îl re-serializază, ordinea cheilor sau spațierea se pot schimba și digestul nu va mai coincide.
Recalculează HMAC-ul peste timestamp + "." + rawBody folosind secretul tău.
Compară în timp constant (crypto.timingSafeEqual în Node). Un simplu === scurge informații despre timp.
Verifică timestamp-ul să fie recent — cinci minute de toleranță este o valoare implicită bună. Timestamp-ul se află în payload-ul semnat, deci un atacator nu poate reda o cerere veche cu un timestamp nou.
O implementare completă este pe pagina Example Server.
Reîncercări
O livrare care eșuează este reîncercată automat.
| Attempts | 3 (prima încercare plus 2 reîncercări) |
| Backoff | 1 secundă, apoi 5 secunde |
| Retried on | Erori de rețea, timeout-uri, 408, 429 și orice 5xx |
| Not retried on | Orice alt 4xx — acestea înseamnă că endpoint-ul tău a respins cererea intenționat |
Din cauza reîncercărilor, endpoint-ul tău poate primi același eveniment de două ori. Folosește X-TicketWave-Delivery ca cheie de idempotency: reține id-urile pe care le-ai procesat și ignoră repetările.
Livrările nu sunt ordonate. Dacă două tichete sunt create în același moment, cererile pot ajunge în oricare ordine — folosește câmpul timestamp din body dacă ordinea contează pentru tine.
Istoricul Livrărilor
Pagina Webhooks din dashboard listează fiecare livrare cu statusul ei, codul de răspuns, durata și numărul de încercări. Deschide un rând pentru a vedea payload-ul exact al cererii trimise și răspunsul returnat de serverul tău.
Livrările eșuate pot fi retrimise din pagina de detalii cu Retry Webhook. Aceasta trimite din nou payload-ul original către același endpoint și înregistrează o livrare nouă.
Istoricul este păstrat timp de 30 de zile, apoi este curățat automat.
Depanare
| Problem | Fix |
|---|---|
| Endpoint-ul nu poate fi salvat | URL-ul trebuie să fie https:// și să se rezolve către o adresă publică |
| Totul apare ca eșuat, fără cod de răspuns | Cererea nu a ajuns niciodată la tine — timeout, eșec DNS sau conexiune refuzată |
| Semnătura nu se potrivește niciodată | Faci hash pe body-ul pars-at în loc de bytes-urile raw, sau ai uitat prefixul timestamp + "." |
| Livrările se opresc după un timp | Verifică dacă hostul tău a început să returneze 4xx — acestea nu sunt reîncercate |
| Un eveniment nu ajunge niciodată | Endpoint-ul nu este abonat la acel tip, sau serverul a pierdut premium |
| Evenimente duplicate | Așteptat la reîncercări — deduplicate pe X-TicketWave-Delivery |
Pașii următori
- Event Reference (Fiecare eveniment și payload-ul său)
- Example Server (Un receptor Express rulabil)
- Log Channels (Aceleași evenimente, dar postate în Discord)
How is this guide?
