TicketWave Logo

Event Reference

Every webhook event type and the exact payload TicketWave sends.

Event Reference

Six event types can be subscribed to per endpoint. Every request uses the same envelope — event, timestamp, guild_id and data — and only the data object differs.

EventFires when
ticket.createdA ticket is opened
ticket.closedA ticket is closed
ticket.updatedAnything else changes on an open ticket
message.sentA member or staff writes in a ticket
blacklist.addedA member is blacklisted
blacklist.removedA blacklist entry is lifted

Fields that cannot be resolved are sent as null rather than being omitted — so you can rely on the keys existing. A username is null when Discord did not return the user.

Shared fields

Every ticket event carries these:

FieldTypeDescription
ticket_idstringThe readable ticket id from your pattern, e.g. ticket-1042
ticket_num_idnumberThe running ticket number, e.g. 1042
channel_idstringThe Discord channel of the ticket
categorystring | nullCategory name, null if the ticket has none
userobject | nullThe ticket owner as { id, username }

ticket.created

Sent right after the ticket channel exists.

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

This fires when the ticket is opened, which is before the member has written anything. If you need the first message, listen for message.sent as well.


ticket.closed

{
  "event": "ticket.closed",
  "timestamp": "2026-08-26T07:45:02.000Z",
  "guild_id": "123456789012345678",
  "data": {
    "ticket_id": "ticket-1041",
    "ticket_num_id": 1041,
    "channel_id": "998877665544332211",
    "category": "💸 Payment",
    "user": { "id": "987654321098765432", "username": "Luna" },
    "closed_by": { "id": "112233445566778899", "username": "Staff_01" },
    "reason": "Issue resolved",
    "closed_at": "2026-08-26T07:45:02.000Z"
  }
}
FieldTypeDescription
closed_byobjectWho closed it. Automatic closes report the bot
reasonstring | nullThe close reason, null if none was given

ticket.updated

The catch-all for changes to an open ticket. action tells you what changed, changes carries the details of that specific action.

{
  "event": "ticket.updated",
  "timestamp": "2026-08-26T14:02:19.000Z",
  "guild_id": "123456789012345678",
  "data": {
    "ticket_id": "ticket-1038",
    "ticket_num_id": 1038,
    "channel_id": "998877665544332211",
    "category": "🤖 Support",
    "user": { "id": "987654321098765432", "username": "Luna" },
    "action": "ticket_priority:add",
    "changes": { "priority": "high" },
    "reason": null,
    "updated_by": { "id": "112233445566778899", "username": "Staff_01" }
  }
}

Possible action values

actionMeaningchanges contains
ticket_claim:addA staff member claimed the ticket(empty)
ticket_unclaim:addThe claim was released(empty)
ticket_priority:addPriority changedpriority
ticket_rename:addThe channel was renamednew_name
ticket_remind:addA reminder was sent(empty)
ticket_feedback:addThe member rated the ticketstar_count, feedback
ticket_schedule_close:addA close was scheduledduration, schedule_time
ticket_request_close:addStaff asked the member to closeduration, request_duration_time
ticket_request_close_accept:addThe member accepted(empty)
ticket_request_close_deny:addThe member declined(empty)
ticket_close_cancel:addA running close was cancelled(empty)
ticket_additional_access:addA user or role was added to the ticketentity_type, entity_id, reason
ticket_additional_access:removeA user or role was removedentity_type, entity_id, reason

Treat this list as open-ended. New actions are added as TicketWave grows, and they arrive as ticket.updated. Switch on the actions you care about and ignore the rest instead of throwing on unknown values.

Answering a ticket step does not produce an event. A ticket with many steps would otherwise flood your endpoint while the member is still filling in the form.


message.sent

Sent for every human message inside an open ticket. Messages from bots — including TicketWave itself — are skipped.

{
  "event": "message.sent",
  "timestamp": "2026-08-26T22:10:55.000Z",
  "guild_id": "123456789012345678",
  "data": {
    "ticket_id": "ticket-1040",
    "ticket_num_id": 1040,
    "channel_id": "998877665544332211",
    "message_id": "1234567890123456789",
    "content": "Hello, how can I help you?",
    "author": { "id": "112233445566778899", "username": "Staff_01" },
    "is_staff": true,
    "sent_at": "2026-08-26T22:10:55.000Z"
  }
}
FieldTypeDescription
contentstringThe raw message text. Empty for attachment-only messages
authorobject{ id, username } of the sender
is_staffbooleantrue if the sender has a configured support role

This is the highest volume event by a wide margin — a busy server produces one request per message. Subscribe to it only if you genuinely need message-level data, and make sure your receiver answers quickly.


blacklist.added

Not tied to a ticket, so this payload has no ticket_id.

{
  "event": "blacklist.added",
  "timestamp": "2026-08-26T18:33:47.000Z",
  "guild_id": "123456789012345678",
  "data": {
    "user": { "id": "111223344556677889", "username": "BadActor" },
    "reason": "Spam",
    "added_by": { "id": "112233445566778899", "username": "Staff_01" }
  }
}

blacklist.removed

{
  "event": "blacklist.removed",
  "timestamp": "2026-08-26T18:40:12.000Z",
  "guild_id": "123456789012345678",
  "data": {
    "user": { "id": "111223344556677889", "username": "BadActor" },
    "removed_by": { "id": "112233445566778899", "username": "Staff_01" }
  }
}

Test events

The Send test event button delivers a real, signed request whose data is just:

{
  "event": "ticket.created",
  "timestamp": "2026-08-26T12:00:00.000Z",
  "guild_id": "123456789012345678",
  "data": { "test": true }
}

The event is the first type the endpoint is subscribed to. Check for data.test if you want to skip test deliveries in production logic.

Next Steps

How is this guide?