Close
Triggered when a ticket is closed
Event Type
"ticket.close"Description
This event is triggered when a ticket is closed by any means - staff command, button, auto-close, or other methods.
Payload Structure
Prop
Type
Participant
Prop
Type
Bots are excluded, so messages from Tickety itself and from other bots never appear.
Response times are measured per side of the conversation. A staff member's response time is the gap between the last message from a ticket user and their reply, with the first one measured from the moment the ticket was opened. A ticket user's response time is the gap between the last staff message and their reply, so their opening message has nothing to measure against. Only the first reply after the other side speaks counts, so a burst of follow up messages does not lower the average.
Example Payload
{
"type": "ticket.close",
"payload": {
"ticketId": "TKT-1234",
"panelId": "support-panel",
"channel": {
"id": "1140972530400776294",
"name": "ticket-0001"
},
"creatorId": "713115896805064856",
"closerId": "280158289667555328",
"closeReason": "Issue resolved!",
"openDate": "2024-01-18T15:30:00.000Z",
"closeDate": "2024-01-18T16:45:00.000Z",
"transcript": "https://tickety.top/transcripts/GdaWKdWF6A0m1Hs7W9P",
"participants": [
{
"id": "713115896805064856",
"messages": 14,
"averageResponseTime": 182.4,
"staff": false
},
{
"id": "280158289667555328",
"messages": 9,
"averageResponseTime": 46.75,
"staff": true
},
{
"id": "451230862009171968",
"messages": 1,
"averageResponseTime": null,
"staff": true
}
]
}
}Example Usage
app.post('/webhook', (req, res) => {
const { type, payload } = req.body;
if (type === 'ticket.close') {
const duration = new Date(payload.closeDate) - new Date(payload.openDate);
const hours = Math.floor(duration / (1000 * 60 * 60));
console.log(`Ticket ${payload.ticketId} closed`);
console.log(`Duration: ${hours} hours`);
console.log(`Reason: ${payload.closeReason || 'No reason provided'}`);
if (payload.transcript) {
console.log(`Transcript: ${payload.transcript}`);
// Archive transcript to your system
await archiveTranscript(payload.transcript, payload.ticketId);
}
// Record how much each staff member handled and how fast they replied
for (const participant of payload.participants.filter(p => p.staff)) {
console.log(`${participant.id}: ${participant.messages} messages`);
await recordStaffActivity({
userId: participant.id,
ticketId: payload.ticketId,
messages: participant.messages,
averageResponseTime: participant.averageResponseTime,
});
}
// Update ticket status in your database
await updateTicketStatus(payload.ticketId, 'closed');
}
res.status(200).send('OK');
});Use Cases
- Archive transcripts to your own storage
- Calculate ticket resolution times
- Update ticket status in external systems
- Send closure notifications
- Generate analytics on close reasons
- Track staff workload and response speed per ticket
- Spot tickets where the creator went quiet or replied slowly