# Create (/api/events/tickets/create)



## Event Type [#event-type]

```ts
"ticket.create"
```

## Description [#description]

This event is triggered whenever a new ticket is created in your server, whether through a ticket panel button, slash command, or any other method.

## Payload Structure [#payload-structure]

<TypeTable
  type="{
  ticketId: {
    description: 'Unique identifier for the ticket',
    type: 'string',
  },
  panelId: {
    description: 'ID of the panel used to create the ticket',
    type: 'string',
  },
  channel: {
    description: 'Discord channel information',
    type: '{ id: string; name: string; }',
  },
  creatorId: {
    description: 'Discord user ID of who created the ticket',
    type: 'string',
  },
  openDate: {
    description: 'ISO 8601 timestamp when the ticket was created',
    type: 'string',
  },
  questions: {
    description: 'Optional form questions and answers if a form was filled. Text displays are not included',
    type: `Array<{
question: string;
answer: string;
required: boolean;
style?: &#x22;SHORT&#x22; | &#x22;PARAGRAPH&#x22; | &#x22;ROLE_SELECT&#x22; | &#x22;CHANNEL_SELECT&#x22;
  | &#x22;USER_SELECT&#x22; | &#x22;OPTION_SELECT&#x22; | &#x22;CHECKBOX&#x22; | &#x22;IMAGE_UPLOAD&#x22;;
upload: UploadReference | null;
}> | undefined`,
  },
}"
/>

## Upload answers [#upload-answers]

Images uploaded to an **Image Upload** form question are stored privately and have no permanent
link. Those questions carry an `upload` object which you exchange for the image using your HTTP
events token. See [Uploads](/api/uploads) for the endpoint.

`answer` is set to the same URL as `upload.url`, so a consumer that only reads `answer` still
gets something it can fetch.

<TypeTable
  type="{
  scope: {
    description: 'Always &#x22;tickets&#x22; for this event',
    type: '&#x22;tickets&#x22;',
  },
  id: {
    description: 'The ticketId the upload was submitted with',
    type: 'string',
  },
  filename: {
    description: 'The stored filename',
    type: 'string',
  },
  url: {
    description: 'Call this with your token to fetch the image',
    type: 'string',
  },
}"
/>

## Example Payload [#example-payload]

```json
{
  "type": "ticket.create",
  "payload": {
    "ticketId": "TKT-1234",
    "panelId": "support-panel",
    "channel": {
      "id": "1140972530400776294",
      "name": "ticket-0001"
    },
    "creatorId": "713115896805064856",
    "openDate": "2024-01-18T15:30:00.000Z",
    "questions": [
      {
        "question": "What is your issue?",
        "answer": "I need help with billing",
        "required": true,
        "upload": null
      },
      {
        "question": "Upload a screenshot",
        "answer": "https://tickety.top/api/uploads/tickets/TKT-1234/a1b2c3d4.webp",
        "required": false,
        "upload": {
          "scope": "tickets",
          "id": "TKT-1234",
          "filename": "a1b2c3d4.webp",
          "url": "https://tickety.top/api/uploads/tickets/TKT-1234/a1b2c3d4.webp"
        }
      }
    ]
  }
}
```

## Example Usage [#example-usage]

```ts
app.post('/webhook', (req, res) => {
  const { type, payload } = req.body;

  if (type === 'ticket.create') {
    console.log(`New ticket created!`);
    console.log(`Ticket ID: ${payload.ticketId}`);
    console.log(`Creator: ${payload.creatorId}`);
    console.log(`Channel: ${payload.channel.name}`);
    
    // If form questions were answered
    if (payload.questions) {
      console.log('Form responses:');
      payload.questions.forEach(q => {
        console.log(`  ${q.question}: ${q.answer}`);
      });
    }
    
    // Send notification to your system
    await notifyNewTicket(payload);
  }

  res.status(200).send('OK');
});
```

## Use Cases [#use-cases]

* Send notifications to external systems when tickets are created
* Log ticket creation for analytics
* Automatically assign tickets based on form responses
* Create corresponding tickets in your own helpdesk system
* Track ticket creation metrics
