# HTTP Events (/api/events)



## Overview [#overview]

Tickety can send HTTP webhook events to your custom endpoint whenever certain actions occur in your server. This allows you to integrate Tickety with your own systems, automate workflows, or build custom integrations.

HTTP Events is configured under **Settings**, in **Advanced Settings**. It is not the same thing as the **Integrations** page under **Server**. HTTP Events sends data out of Tickety to a server you run, while [Integrations](/server/integrations) brings data into Tickety from a service you already use.

<Callout type="info">
  HTTP Events are available to all servers with a daily limit of **150 requests** for free servers. Premium servers have **unlimited requests**.
</Callout>

## Getting Started [#getting-started]

1. Navigate to your server's Dashboard
2. Open **Settings** and expand **Advanced Settings**
3. Enable **HTTP Events**
4. Enter your HTTP events endpoint URL (not a Discord webhook)
5. Copy your **authentication token** (automatically generated)

## How It Works [#how-it-works]

When an event occurs in your server (e.g., a ticket is created), Tickety sends a POST request to your configured webhook URL with the following structure:

```json
{
  "type": "ticket.create",
  "payload": {
    // Event-specific data
  }
}
```

### Authentication [#authentication]

All requests include an `Authorization` header with your unique token:

```ts
const authToken = request.headers.get("Authorization");
// Verify this matches your token from the dashboard
```

<Callout type="warn">
  Keep your authentication token secret! Anyone with this token can send fake events to your endpoint, and it also grants access to your server's uploaded images through the [Uploads API](/api/uploads).
</Callout>

### Uploaded images [#uploaded-images]

Images that users upload as answers to ticket forms or applications are stored privately and are
not included in the event payload. Those questions carry an `upload` object instead, which you
exchange for the image using the same token. See [Uploads](/api/uploads).

## Rate Limits [#rate-limits]

| Tier    | Daily Limit  | Reset Time |
| ------- | ------------ | ---------- |
| Free    | 150 requests | 00:00 UTC  |
| Premium | Unlimited    | N/A        |

The rate limit counter resets daily at midnight UTC. Once you reach your limit, no more events will be sent until the next day.

## Choosing which events are sent [#choosing-which-events-are-sent]

Events are split into five categories, and each one has its own toggle in the dashboard. Every category is enabled by default, so a new endpoint receives everything until you turn something off.

1. Navigate to your server's Dashboard
2. Open **Settings** and expand **Advanced Settings**
3. Under **Event Categories**, turn any category on or off

| Category         | Contains                                                                                                   |
| ---------------- | ---------------------------------------------------------------------------------------------------------- |
| **Tickets**      | Created, closed, claimed, unclaimed, renamed, moved, transferred, priority changed, users added or removed |
| **Applications** | Submitted, accepted, denied                                                                                |
| **Verification** | Passed, failed                                                                                             |
| **Members**      | Joined the server, left the server                                                                         |
| **Giveaways**    | Started, ended, joined, rerolled                                                                           |

Toggles apply to a whole category, not to individual event types. If you only care about some events inside a category, leave the category on and filter on `type` in your own handler.

<Callout type="info">
  Events in a disabled category are skipped before they are sent, so they never count toward your daily request limit. Turning off categories you do not use is the easiest way to stay under the free tier limit.
</Callout>

The **Members** category covers server joins and leaves for every member. These events are sent whenever HTTP Events is on, even without welcome or leave messages set up.

## Event Types [#event-types]

Tickety supports the following event types. Each heading below is one category, matching the toggles described in [Choosing which events are sent](#choosing-which-events-are-sent).

### Ticket Events (Tickets category) [#ticket-events-tickets-category]

* `ticket.create` - A ticket was created
* `ticket.close` - A ticket was closed
* `ticket.rename` - A ticket was renamed
* `ticket.priority` - A ticket's priority was changed
* `ticket.move` - A ticket was moved to a different category
* `ticket.transfer` - A ticket was transferred to a different panel
* `ticket.claim` - A ticket was claimed by a staff member
* `ticket.unclaim` - A ticket was unclaimed
* `ticket.add` - A user was added to a ticket
* `ticket.remove` - A user was removed from a ticket

### Application Events (Applications category) [#application-events-applications-category]

* `application.submit` - An application was submitted
* `application.accept` - An application was accepted
* `application.deny` - An application was denied

### Verification Events (Verification category) [#verification-events-verification-category]

* `verification.pass` - A user passed verification
* `verification.fail` - A user failed verification

### Member Events (Members category) [#member-events-members-category]

* `member.join` - A member joined the server
* `member.leave` - A member left the server

### Giveaway Events (Giveaways category) [#giveaway-events-giveaways-category]

* `giveaway.start` - A giveaway was created
* `giveaway.end` - A giveaway ended and winners were drawn
* `giveaway.join` - A member entered a giveaway
* `giveaway.reroll` - Winners were rerolled

<Callout type="warn">
  `giveaway.join` fires once per entry, so a popular giveaway can spend a free server's whole daily
  limit in one evening. Turn the Giveaways category off if you only want the other events, or upgrade
  to premium for unlimited requests.
</Callout>

## Example Implementation [#example-implementation]

Here's a simple Express.js server that receives Tickety events:

```ts
import express from 'express';

const app = express();
app.use(express.json());

const TICKETY_AUTH_TOKEN = 'your-token-from-dashboard';

app.post('/tickety-webhook', (req, res) => {
  // Verify authentication
  const authToken = req.headers.authorization;
  
  if (authToken !== TICKETY_AUTH_TOKEN) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  const { type, payload } = req.body;

  // Handle different event types
  switch (type) {
    case 'ticket.create':
      console.log(`New ticket created: ${payload.ticketId}`);
      console.log(`Channel: ${payload.channel.name}`);
      break;
    
    case 'ticket.close':
      console.log(`Ticket closed: ${payload.ticketId}`);
      console.log(`Reason: ${payload.closeReason}`);
      break;
    
    // Handle other event types...
    default:
      console.log(`Unknown event type: ${type}`);
  }

  res.status(200).json({ success: true });
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});
```

## Security Considerations [#security-considerations]

1. **Always verify the authentication token** - Check the `Authorization` header matches your token
2. **Use HTTPS when possible** - HTTPS is recommended for production to ensure encryption, but HTTP is also supported
3. **Validate the payload** - Check that the event data matches your expected structure
4. **Don't expose your token** - Never commit your token to version control or share it publicly
5. **Implement rate limiting** - Protect your endpoint from potential abuse
