TicketWave Logo
Webhooks

Огляд

Отримуйте події TicketWave як підписані HTTP-запити у власній програмі.

Webhooks

Вебхук — це HTTP-запит, який TicketWave надсилає вам. Щоразу, коли у вашому сервері щось відбувається — відкривається тікет, учасника додають до чорного списку — TicketWave надсилає POST із JSON-тілом на URL, який належить вам.

У цьому й різниця з Log Channels: log channels записують embed у Discord для людей, а вебхуки передають сирі події у ваш код.

Вебхуки — це преміумна функція. Без преміуму кінцеві точки не можна створювати, і жодні події не доставляються.

Create an Endpoint

Open the endpoints page

Server dashboard → WebhooksEndpoints.

Add an endpoint

Click Add Endpoint and fill in two fields:

FieldDescription
Endpoint URLThe https:// URL that receives the requests
Event TypesWhich events this endpoint should receive

An endpoint only receives the types you tick. Selecting none is not allowed — pick at least one.

Copy the signing secret

TicketWave generates a signing secret (whsec_…) the moment the endpoint is created. Open the endpoints list, reveal it with the eye icon and copy it into your application's configuration.

Treat the secret like a password. Anyone who has it can forge requests that pass your signature check. Keep it in an environment variable, never in your repository.

Send a test event

Use the Send test event button (the paper plane) on the endpoint row. It delivers a real, fully signed request with "test": true in the payload, so you can confirm your receiver works before a real ticket depends on it.

The result shows up in the Webhooks history like any other delivery.

Endpoint Requirements

RequirementDetail
Schemehttps:// only — http:// is rejected
HostMust be publicly resolvable. Private, loopback, link-local and CGNAT addresses are refused
ResponseAny 2xx status counts as success
TimeoutYou have 10 seconds to respond
RedirectsNot followed. A 3xx counts as a failure
LimitUp to 5 endpoints per server

The host check happens both when you save the endpoint and before every single delivery, so a domain that later starts resolving to an internal address stops being delivered to.

The Request

Every delivery is a POST with a JSON body.

Headers

HeaderExampleMeaning
Content-Typeapplication/jsonAlways JSON
User-AgentTicketWave-Webhooks/1.0.5The bot version that sent it
X-TicketWave-Eventticket.createdThe event type
X-TicketWave-Deliverywh_3f2a…Unique id for this delivery
X-TicketWave-Timestamp1786224191Unix seconds, part of the signature
X-TicketWave-Signaturesha256=9f86d0…HMAC of the request

Body

Every payload uses the same envelope. Only data differs per event type:

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

See the Event Reference for the data object of every type.

Verifying the Signature

Anyone who discovers your endpoint URL can send it a POST request. The signature is how you tell a real TicketWave delivery from a forged one.

Always verify. An unverified endpoint that creates or closes things in your system is an open door.

How the signature is built

TicketWave joins the timestamp and the raw request body with a dot, and runs HMAC-SHA256 over the result using your endpoint secret:

signed_payload = X-TicketWave-Timestamp + "." + raw_request_body
signature      = HMAC_SHA256(signed_payload, your_endpoint_secret)

The header carries that digest hex-encoded and prefixed: sha256=<digest>.

What your receiver must do

Read the raw body. Verify against the exact bytes you received. If your framework parses JSON first and you re-serialise it, key order or spacing may change and the digest will not match.

Recompute the HMAC over timestamp + "." + rawBody with your secret.

Compare in constant time (crypto.timingSafeEqual in Node). A plain === leaks timing information.

Check the timestamp is recent — five minutes of tolerance is a good default. The timestamp is inside the signed payload, so an attacker cannot replay an old request with a fresh timestamp.

A complete implementation is on the Example Server page.

Retries

A delivery that fails is retried automatically.

Attempts3 (the first try plus 2 retries)
Backoff1 second, then 5 seconds
Retried onNetwork errors, timeouts, 408, 429 and any 5xx
Not retried onEvery other 4xx — those mean your endpoint rejected the request on purpose

Because of retries your endpoint can receive the same event twice. Use X-TicketWave-Delivery as an idempotency key: remember the ids you have processed and ignore repeats.

Deliveries are not ordered. If two tickets are created at the same moment, the requests can arrive in either order — use the timestamp field in the body if order matters to you.

Delivery History

The dashboard's Webhooks page lists every delivery with its status, response code, duration and number of attempts. Open a row to see the exact request payload that was sent and the response your server returned.

Failed deliveries can be re-sent from the detail page with Retry Webhook. It sends the original payload again to the same endpoint and records a new delivery.

The history is kept for 30 days, then cleaned up automatically.

Troubleshooting

ProblemFix
The endpoint cannot be savedThe URL must be https:// and resolve to a public address
Everything shows as failed with no response codeThe request never reached you — timeout, DNS failure or connection refused
Signature never matchesYou are hashing the parsed body instead of the raw bytes, or forgot the timestamp + "." prefix
Deliveries stop after a whileCheck whether your host started returning 4xx — those are not retried
An event never arrivesThe endpoint is not subscribed to that type, or the server lost premium
Duplicate eventsExpected on retries — deduplicate on X-TicketWave-Delivery

Next Steps

How is this guide?