> For the complete documentation index, see [llms.txt](https://developer.vario-software.de/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.vario-software.de/documentation/webhooks/faq.md).

# FAQ

### How do I find out which events exist?

Ask the ERP:

```
GET /cmn/system/app-message-webhook/destinations
```

It lists every available queue with a description.

→ [Webhooks Introduction](/documentation/webhooks/introduction.md)

### My webhook is registered but never fires.

Work through this in order:

1. **Is the App active for this tenant?** Events for inactive apps are discarded before any delivery record is created — so you won't even find a failed delivery.
2. **Does that topic actually get emitted?** The destinations list is generated and, for documents, contains *every* category/transition combination. Some are never emitted. Registering one succeeds and stays silent forever.
3. **Are deliveries failing?** Query `system.queryAppMessageEntry` and read `recipients.response`.
4. **Are you answering in time?** The timeout is **5 seconds**.
5. **Are you returning 401?** See [above](#vario-calls-my-app-and-my-app-answers-401-whats-wrong).
6. **Did you suppress it yourself?** Check whether your own write set the suppression header.

### Why does my webhook handler run twice?

Almost always a **second registration** you didn't intend. The identity of a subscription includes the **full URL** — so if the URL changed (a new domain, a different `WEBHOOK_HOST` in local development, a path convention change), the old subscription still exists and still fires.

The other cause is registering the same webhook from two places, for example a per-channel registration plus an `always()` step that also registers it.

### How do I stop an infinite webhook loop?

If you react to `article.update` by writing back to the article, that write triggers the event again. Send this header on **your** write:

```
x-vario-suppress-own-webhooks: true
```

It suppresses only **your own** subscriptions; other apps still get the event.

{% hint style="warning" %}
Only the **presence** of the header is checked — not its value. Sending `x-vario-suppress-own-webhooks: false` still suppresses. Omit the header entirely when you want the event.

It also only works if VARIO can identify you as the caller, which is why the `User-Agent` must carry your app identifier.
{% endhint %}

### How long may my handler take?

Under 5 seconds — so in practice: **acknowledge first, then work.** Return `200` immediately and continue processing asynchronously. Otherwise the delivery is recorded as failed and retried even though you handled it.

### Are webhooks ordered? Delivered exactly once?

No and no. Delivery is **at least once** with **no ordering guarantee**, up to **3 attempts**, after which it is abandoned permanently. Handlers must be idempotent.

Note that in-memory duplicate protection does not span processes — if you run several instances you need a shared guard.

### Why does my cron webhook handler receive a string instead of an object?

Cron payloads can arrive **double-encoded**. Accept both:

```javascript
const payload = typeof req.body === 'string' ? JSON.parse(req.body) : req.body;
```

Also remember a cron webhook needs **two** things: a subscription with owner `APP`, *and* a scheduled task with the same destination.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.vario-software.de/documentation/webhooks/faq.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
