> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ventry.es/llms.txt
> Use this file to discover all available pages before exploring further.

# Webhooks (coming soon)

> What is planned, and how to solve it in the meantime.

<Note>
  Outbound webhooks are **not available yet**. This page describes what is planned
  so you can design your integration without having to redo it later.
</Note>

## In the meantime: incremental polling

For almost every case, polling every 30 seconds with `updated_since` or `since`
gives you the same information at far lower complexity. See
[Pagination](/en/pagination).

| What you want to know | How                                          |
| --------------------- | -------------------------------------------- |
| Who has come in       | `GET /tickets?status=used&updated_since=...` |
| Denied scans          | `GET /checkins?result=denied&since=...`      |
| New sales             | `GET /transactions?since=...`                |
| New top-ups           | `GET /topups?since=...`                      |

With a quota of 120 requests per minute, polling every 30 seconds uses two.

## What is planned

Events that will be emitted:

| Event                      | When                                             |
| -------------------------- | ------------------------------------------------ |
| `ticket.created`           | A ticket is created                              |
| `ticket.cancelled`         | A ticket is cancelled                            |
| `ticket.checked_in`        | A ticket is accredited and linked to a wristband |
| `access.denied`            | Access to a zone is denied                       |
| `wristband.pending_review` | Unresolved double accreditation                  |
| `transaction.completed`    | A purchase is recorded                           |
| `topup.completed`          | A top-up is recorded                             |

### Formats

Alongside the native JSON format, there will be direct output to **Discord** and
**Slack** via their incoming webhooks, so operational alerts can be dropped into a
team channel without writing code: duplicate accreditations, denied access at a
specific door, or blocked wristbands.

### Delivery

* `HMAC-SHA256` signature in the `X-Ventry-Signature` header, over the raw body.
* Retries with exponential backoff on non-`2xx` responses.
* Manual redelivery from the VENTRY dashboard.
* **At-least-once delivery**: your receiver will need to be idempotent and
  deduplicate by event identifier.

## What you can do now to prepare

<AccordionGroup>
  <Accordion title="Make your receiver idempotent">
    Whether by polling or by webhook, you will see the same record more than once.
    Deduplicate by the resource `id`, not by arrival order.
  </Accordion>

  <Accordion title="Do not assume ordering">
    A terminal without connectivity syncs in bulk. You may receive a 22:00 sale
    after a 23:00 one. Sort by `occurred_at` on your side.
  </Accordion>

  <Accordion title="Separate ingestion from processing">
    Store what you receive and process it separately. That is what will let you
    swap polling for webhooks without touching your business logic.
  </Accordion>
</AccordionGroup>
