Ticket Lifecycle Hooks
The eight hooks over creating, closing, transferring and locking a ticket.
Overview
The path of a ticket lives here: it opens, its status moves, it is transferred, locked, and finally deleted or resolved on its own.
Two status hooks look alike but are separate: one reports a change made by staff, the other an automatic resolution nobody touched.
Reference
Stopping a ticket opened by staff
Runs when staff open a ticket on behalf of a customer, before anything is written.
Hook::add('gate:ticket.admin_create', 10, function ($set_request, $message, $udata) {
if (Acme::blacklisted((int) ($udata['id'] ?? 0))) return 'No ticket can be opened for this account.';
return null;
});Following a ticket being created
Runs after a ticket is created.
Hook::add('action:ticket.created', 10, function ($ticket) {
// The first message is not a separate parameter; it sits in the ticket.
Acme::classify((int) ($ticket['id'] ?? 0), $ticket['message'] ?? '');
});Following a status change
Runs after the status of a ticket changes.
Hook::add('action:ticket.status_changed', 10,
function ($ticket, $old_status, $new_status, $new_cstatus) {
// Custom states are a second axis beside the base state.
if ($new_status === 'solved') Acme::stopSlaClock((int) ($ticket['id'] ?? 0));
});Following an automatic resolution
Runs when a ticket left without a reply closes itself. Nobody closed it: silence did.
Hook::add('action:ticket.auto_resolved', 10, function ($ticket_id, $ticket, $delayed_day) {
// Nobody closed it: silence did.
Acme::surveyLater($ticket_id, $delayed_day);
});Following staff opening a ticket
Runs when staff open a ticket.
Hook::add('action:ticket.viewed', 10, function ($ticket, $id) {
// The unread mark is already cleared.
Acme::trackHandling($id);
});Following a ticket being transferred
Runs after a ticket is transferred to another customer.
Hook::add('action:ticket.transferred', 10, function ($ticketId, $fromUserId, $toUserId) {
// The history moved with it.
Acme::reindexOwner($ticketId, $toUserId);
});Following a lock change
Runs when a ticket is locked or unlocked. A customer cannot reply to a locked ticket.
Hook::add('action:ticket.lock_changed', 10, function ($ticket, $locked) {
// A customer cannot reply to a locked ticket.
if ($locked === 1) Acme::notifyLocked((int) ($ticket['user_id'] ?? 0));
});Following a ticket being deleted
Runs after a ticket is deleted.
Hook::add('action:ticket.deleted', 10, function ($ticket_id) {
// No record is passed: keep the content beforehand if you need it.
Acme::dropFromIndex('ticket', $ticket_id);
});Pitfalls
The hook runs when staff open a ticket, but the unread flag is cleared before it. You cannot answer "was this new" from here; track the first opening separately.
Unlike other deletion hooks no ticket record is passed. If you need its title, owner or content you must have kept it beforehand; by the time the hook runs there is nowhere left to read it from.
Related Articles
- Support Ticket Hooks
- Customer Account Hooks
- How Hooks Work
Thanks for your feedback!
Our support team is here around the clock for anything you can't find above.