
# Webhooks

Webhooks lader <span data-t="appName">Your AI Connector</span> automatisk give besked til dine andre forretningsværktøjer, når der sker noget vigtigt — en ny kontakt oprettes, en aftale bookes, eller en besked modtages. I stedet for manuelt at tjekke for opdateringer, modtager dine forbundne systemer en øjeblikkelig notifikation i det øjeblik, der sker noget.


---

## Hvad er webhooks?

Tænk på en webhook som en automatisk sms mellem to apps. Når der sker noget i <span data-t="appName">Your AI Connector</span> (f.eks. en ny kontakt tilmelder sig), sender platformen øjeblikkeligt en notifikation til et andet system efter dit valg. Du angiver en webadresse (kaldet en "webhook-URL"), hvor disse notifikationer skal sendes hen — denne leveres typisk af dit CRM, din automatiseringsplatform eller din udvikler.

> **Webhooks sender kun data UD af <span data-t="appName">Your AI Connector</span>.** Et webhook er en ensrettet vej *fra* <span data-t="appName">Your AI Connector</span> *til* dine andre værktøjer. Der findes **ingen webhook-URL, der sender kundeemner, kontakter eller beskeder IND i platformen.** For at skubbe et nyt kundeemne ind — fra en hjemmesideformular, dit CRM eller GoHighLevel — foretager dit system i stedet et **API-kald**. Se [API-adgang](api-access.md) (handlingen *Opret en kontakt*) og [Funnels](funnels.md). Det eneste, du skal bruge til den indgående retning, er din **API-nøgle**, som ligger i sin egen sektion — se [API-adgang](api-access.md#generating-your-api-key). Siden **Webhooks**, der beskrives her, er udelukkende til den udgående retning.

::: note
**Bemærk:** Opsætning af webhooks involverer en vis teknisk konfiguration. Hvis du ikke er tryg ved dette, kan du dele denne side med din udvikler eller bruge en automatiseringsplatform som Zapier, Make eller Pabbly, som leverer webhook-URL'er uden behov for kodning.
:::


Almindelige anvendelser inkluderer:

- Synkronisering af nye kontakter til dit CRM.
- Udløsning af et workflow i Zapier, Make eller Pabbly, når et tag tilføjes.
- Underretning af dit team i Slack, når et menneske bliver tilkaldt.
- Opdatering af dit kalendersystem, når en aftale bookes.
- Logning af samtaleoversigter til din database.

---

## Opsætning af webhooks

1. Klik på **Indstillinger** (tandhjulsikonet) i venstre sidepanel.
2. Under gruppen **Integrationer** i indstillingspanelet skal du klikke på **Webhooks**.


På en konto, hvor der endnu ikke er konfigureret nogen webhooks, ser siden således ud:


3. Klik på **New webhook** øverst til højre. En formular åbnes direkte på siden:


4. Udfyld:
   - **Endpoint-URL** — den webadresse, som <span data-t="appName">Your AI Connector</span> sender begivenhedsnotifikationer til. Du får denne fra dit eksterne system (CRM, automatiseringsplatform eller egen server).
   - **Navn** — en etiket, som du kan genkende senere (f.eks. "Slack-advarsler" eller "CRM-synkronisering"). Kun til din egen reference.

> **Din webhook URL skal være en offentligt tilgængelig `https://` adresse.** Almindelige `http://` adresser, `localhost` eller adresser på private netværk samt platform-interne adresser afvises, når du gemmer. For at teste fra din egen maskine skal du bruge en offentlig tunnel (webhook.site eller ngrok) i stedet for localhost.

5. Under **Events**, skal du klikke på de hændelser, som denne webhook skal modtage — alle 22 er angivet i [De 22 webhook-hændelser](#the-22-webhook-events).
6. *(Valgfrit)* Slå **Forsøg igen ved mislykkede leveringer** til, hvis du vil have <span data-t="appName">Your AI Connector</span> til at blive ved med at forsøge ved en midlertidig fejl — se [Forsøg igen ved mislykkede leveringer](#retrying-failed-deliveries).
7. Klik på **Opret webhook**. Den vises på listen under formularen, og du kan til enhver tid klikke på **Test** på dens række for at sende en eksempel-payload til dit endpoint.

> **Tilladelse påkrævet.** Tilføjelse, redigering eller test af webhooks kræver "rediger"-tilladelse til Integrationer (teammedlemmer med skrivebeskyttet adgang ser en meddelelse om skrivebeskyttelse i stedet for formularen).

> **Signering af en webhook** kræver, at den allerede er gemt først — åbn en eksisterende webhooks række for at redigere den, så vises panelet **Signeringshemmelighed** nederst i redigeringsformularen. Et helt nyt, ikke-gemt udkast har endnu ingen signeringsmulighed — se [Signerede payloads](#signed-payloads-verifying-a-webhook-really-came-from-us) nedenfor.

---

## Én webhook til alle dine klientkonti (bureauer)

Hvis du driver et bureau, behøver du ikke at genskabe den samme webhook på hver klientkonto. På bureaukontoen har webhook-formularen en ekstra til/fra-knap: **Udløs også for alle klientkonti**. Slå den til, og denne webhook modtager også hændelser, der sker på alle klientkonti under dit bureau — ét endpoint, hele bureauet.

Sådan fungerer det:

- **`user`-blokken fortæller dig, hvilken klient en hændelse tilhører.** Hver notifikation indeholder allerede en `user`-blok, der identificerer den konto, hændelsen skete på, så din automatisering kan rute pr. klient.
- **Din webhooks egne indstillinger gælder overalt.** De hændelser, du har valgt, underskriftshemmeligheden og indstillingen for genforsøg bruges også til leveringer til klientkonti.
- **Ingen dobbelte leveringer.** Hvis en klientkonto har sin egen webhook, der peger på den samme URL, bruges den i stedet for den konto-hændelser — den samme hændelse ankommer aldrig to gange til ét endpoint.
- **Klienter kan ikke se den.** Webhooken vises ikke på klientkontoens egen side for webhooks, og klienter kan ikke slå den fra — det er din opgave at administrere den.
- **Pålidelighed spores pr. klientkonto.** Hvis dit endpoint bliver ved med at fejle, slås det automatisk fra for den konto, hvis leveringer fejlede (se [Webhook-pålidelighed](#webhook-reliability)), ikke for hele bureauet på én gang.

Til/fra-knappen vises kun på bureaukonti. Det understøttes også at indstille den via API'et — se feltet `apply_to_sub_accounts` i [Webhooks API](../api/webhooks.md#one-subscription-for-all-client-accounts-agencies).

---

## Tilgængelige udløserbegivenheder

Du kan aktivere eller deaktivere hver af de 22 webhook-hændelser uafhængigt af hinanden. Når en hændelse udløses, sender <span data-t="appName">Your AI Connector</span> en meddelelse til din webhook-URL med de relevante data. Hver hændelse, hvad den betyder, og den `event`-kode, den placerer i payloaden, er angivet samlet i [De 22 webhook-hændelser](#the-22-webhook-events) længere nede på denne side.

> **Godt at vide:** **Opgave oprettet**, **Opgave opdateret** og **Opgave fuldført** kan vælges fuldt ud og gemmes korrekt. **Dagligt resumé oprettet** er også en ny tilføjelse. Se [Webhook for fuldført opgave](#task-completed-webhook) nedenfor for den payload-struktur.

---

## Tag-baserede webhook-udløsere

`subscribed_to_tags` begrænser ikke en webhooks hændelser til et tag. Det indsnævrer kun, hvilke tags der producerer en notifikation om samtaleresumé. For at modtage en anmodning, når et specifikt tag anvendes, skal du indstille en webhook-URL på det pågældende tag under fanen **Tags** for agenten (eller kampagnen).

Selve webhook-formularen har ingen tag-vælger, hverken når du opretter en ny webhook eller redigerer en eksisterende, så `subscribed_to_tags` kan kun læses eller ændres via [Webhooks API](../api/webhooks.md) eller ved at kontakte support.

> **Godt at vide:** Redigering af en eksisterende webhook, der har en `subscribed_to_tags`-liste (omdøbning, ændring af hændelser, aktivering af genforsøg), sletter ikke længere listen — da formularen ikke har nogen tag-vælger, der skal sendes tilbage, efterlader lagring fra denne side den eksisterende liste uberørt. (Dette var en reel fejl før **21. juli 2026**: lagring fra webhook-formularen slettede tidligere listen, fordi den altid sendte en tom tag-liste. Hvis en webhook mistede sin `subscribed_to_tags`-liste før denne dato, skal den konfigureres igen via API'et.)

### Generer resumé for taggede kontakter

Hvor en webhook har en `subscribed_to_tags`-liste, kan du aktivere **Generer resumé**. Når det er aktiveret, genererer <span data-t="appName">Your AI Connector</span> automatisk et samtaleresumé for kontakten, når et af disse tags anvendes, og inkluderer det i webhook-dataene — fuld kontekst uden en separat anmodning.

---

## Test af din webhook

1. Åbn **Indstillinger → Integrationer → Webhooks**.
2. Klik på **Test** på din webhooks række.
3. Tjek dit eksterne system for at bekræfte, at det modtog testdataene.
4. Gennemgå dataformatet for at sikre, at dit system kan parse det korrekt.

For en fuld end-to-end-test skal du sende en besked, der ville udløse en af dine konfigurerede hændelser (en udsendelse eller en indgående besked på en forbundet kanal), og bekræfte, at webhooken udløses med de rigtige data.

::: tip
**Tip:** Brug et værktøj som [webhook.site](https://webhook.site) eller [RequestBin](https://requestbin.com) under udviklingen til at inspicere rå webhook-data, før du forbinder dit produktionssystem.
:::


### Hvad tæller som en vellykket levering

Uanset om du klikker på **Test**, eller begivenheden udløses i virkeligheden, sender vi det samme:

- En **POST**-anmodning (aldrig GET), med body som JSON og `Content-Type: application/json`.
- Overskrifterne oplistet under [Signerede payloads](#signed-payloads-verifying-a-webhook-really-came-from-us). Signaturoverskrifter inkluderes kun, når du har angivet en signeringsnøgle.

Vi betragter leveringen som vellykket, når:

- Dit slutpunkt svarer med **enhver 2xx-status** (200, 201, 204 — alt er fint).
- Det svarer **inden for 30 sekunder**.

Et par ting, der overrasker folk:

- **Svarskroppen ignoreres.** Du behøver ikke at returnere nogen bestemt JSON. En tom 200 er nok.
- **Omdirigeringer tæller som en fejl.** Vi følger dem ikke, så en 301 eller 302 (inklusive en omdirigering med skråstreg til sidst, eller http til https) registreres som en mislykket levering. Gem den endelige URL, ikke en der omdirigerer.
- **Query-strenge understøttes fuldt ud.** `https://your-app.com/hook?token=abc123` sendes præcis som du gemte den, så det fungerer lige så godt at placere et token i query-strengen som at placere det i stien.
- **Din URL skal være `https://` og offentligt tilgængelig.** Adresser, der tilhører <span data-t="appName">Your AI Connector</span>'s egen infrastruktur, afvises, men dine egne endpoints på Google Cloud Functions, Cloud Run, App Engine, Firebase Hosting eller andre steder er fine.
- **En firewall eller et bot-beskyttelseslag foran dit endpoint kan blokere os.** Det mest almindelige tilfælde er Cloudflare: hvis din zone har Bot Fight Mode eller en administreret udfordring slået til, får vores anmodning en "Just a moment..."-udfordringsside med en 403 i stedet for at nå din server — og en server-til-server-anmodning kan aldrig bestå en browser-udfordring, så både **Test**-knappen og rigtige hændelser fejler på samme måde. Test-knappen fortæller dig, når dette sker ("Cloudflare viser en bot-udfordring til vores anmodning"). Løs det i Cloudflare med en Security / WAF-regel, der springer udfordringer over for din webhook-sti (eller for `Webhook-Delivery/1.0` user agent), og klik derefter på **Test** igen.
- **Hvis din firewall i stedet har brug for en IP-tilladelsesliste** (for eksempel Cloudflares gratis abonnement, hvor almindelig Bot Fight Mode ikke kan springes over med en WAF-regel, men en IP Access Rule indstillet til Allow kører før den), kan vi hjælpe: hver levering, uanset om den kommer fra **Test**-knappen eller en live-hændelse, sendes fra én fast IPv4-adresse (ingen intervaller, ingen IPv6, ingen rotation). Kontakt support, så giver vi dig adressen, der skal på tilladelseslisten. Behold [signaturverificering](#signed-payloads-verifying-a-webhook-really-came-from-us) som din faktiske tillidskontrol, da den validerer hver payload uanset hvor den kom fra.
- **Testresultatet fortæller dig præcis, hvad dit endpoint svarede.** En mislykket test viser nu den virkelige årsag (den HTTP-status dit endpoint returnerede, en timeout, eller at vi slet ikke kunne nå adressen) i stedet for en generisk fejl, og en test på en gemt webhook sendes signeret, når signering er slået til, præcis som en live-hændelse.

### Brug af n8n, Make eller Zapier ("Test-URL" vs "Produktions-URL")

Automationsplatforme giver dig normalt to forskellige webhook-adresser, og det forvirrer ofte folk:

- En **Test-URL** (i n8n indeholder den `/webhook-test/`). Denne modtager kun data, mens du aktivt overvåger lærredet og lige har klikket på **Listen for test event** (eller **Test workflow**). Den fanger en enkelt hændelse og stopper derefter med at lytte – så hvis du klikker på **Test** i <span data-t="appName">Your AI Connector</span> flere gange i træk, fanges kun den første, og kun hvis lyttevinduet er aktivt i det præcise øjeblik. For at teste: Klik først på **Listen for test event** i n8n, vend derefter tilbage til <span data-t="appName">Your AI Connector</span> og klik på **Test** én gang.
- En **Produktions-URL** (i n8n indeholder den `/webhook/`, ingen `-test`). Dette er den, du skal indsætte i <span data-t="appName">Your AI Connector</span> til live-hændelser. Den virker kun, når dit workflow er sat til **Aktivt**. Hvis workflowet ikke er aktivt, afviser n8n anmodningen med en "404 / webhook not registered"-fejl, selvom <span data-t="appName">Your AI Connector</span> sendte dataene korrekt.

Kort sagt: test med Test-URL'en, mens du lytter, men for at webhooken skal fortsætte med at virke på rigtige kontakter, skal du gemme **Produktions-URL'en** i <span data-t="appName">Your AI Connector</span> og sikre dig, at workflowet er **Active**.

---

## Webhook-dataformat

Når en webhook udløses, sender <span data-t="appName">Your AI Connector</span> strukturerede data (JSON) til din webhook-URL. Hvis du bruger en automatiseringsplatform som Zapier eller Make, parser den automatisk disse data for dig. Hvis du bygger en brugerdefineret integration:

```json
{
  "event": "contactCreated",
  "contact": { "id": "<contact-id>", "first_name": "Jane", "...": "..." },
  "campaign": { "id": "<campaign-id>", "name": "AI Receptionist", "status": "Live" },
  "agent": { "id": "<agent-id>", "name": "Front Desk" },
  "user": { "id": "<account-id>", "email": "owner@example.com" }
}
```

| Felt | Beskrivelse |
|---|---|
| `event` | Den nøjagtige hændelsesstreng, der udløste meddelelsen (f.eks. `contactCreated`, `booked`). Dette er **ikke** den visningsetiket, der vises på hændelseslisten; hver etiket og dens tilhørende kode findes i [De 22 webhook-hændelser](#the-22-webhook-events). |
| `contact` | Den kontakt, hændelsen handler om, eller `null` for hændelser, der ikke er knyttet til en kontakt (såsom `creditsRecharged`). |
| `campaign` | Den kampagne, kontakten tilhører, eller `null` hvis der ikke er nogen. |
| `agent` | Den agent, der håndterer samtalen, eller `null` hvis der ikke er nogen. |
| `user` | Grundlæggende identitetsoplysninger for den konto, der ejer dataene. |

> **`campaign` eller `agent` — normalt den ene, ikke begge.** Hvis din konto bruger agenter, er dine kontakter tilknyttet en agent frem for en kampagne, så `campaign` ankommer som `null`, og `agent` fortæller dig, hvem der håndterede den. Ældre kampagnebaserede konti ser det omvendte. Læs det felt, der er udfyldt; antag ikke, at `campaign` altid er til stede.

> **`agent`-blokken ankom den 15. august 2026.** Den findes sammen med `campaign` i begivenheder knyttet til en samtale – en afsluttet chat, forstyr ikke, en genoptagelse, en de-arkivering, en AI-pause, en ny besked, et samtaleressumé og den webhook, du kan indstille på et tag – og indeholder den håndterende agents `id` og `name`, eller `null`, når ingen agent er involveret. Den er rent additiv: alle felter, du allerede modtager, er uændrede, så en modtager, du har bygget før denne dato, fortsætter med at fungere uden behov for opdateringer.

Nogle hændelser tilføjer deres egen ekstra blok på øverste niveau. For eksempel tilføjer **Appointment Booked** en `appointment`-blok (se [Appointment Booked Webhook](#appointment-booked-webhook)), **New Message** tilføjer en fuld `message`-blok med teksten (se [New Message Webhook](#new-message-webhook)), og **Deliveries** og **Reads** tilføjer en kort `message`-blok med kun beskedens ID og status (se [Deliveries and Reads Webhook](#deliveries-and-reads-webhook)).

> **Deliveries og Reads fortæller dig hvilken besked, men ikke hvad den sagde.** De indeholder en `message`-blok med beskedens `id` og `status` — og det `id` er det samme `messageId`, som [send message endpoint](../api/messages.md#send-a-message) returnerer, så du kan matche en leverings- eller læsekvittering med den præcise besked, du sendte — men ingen beskedtekst. **Replies** indeholder slet ingen `message`-blok. Hvis du har brug for ordene, der blev sendt eller modtaget, skal du abonnere på **New Message** ved siden af dem.

> **To ting du skal vide, før du skriver din modtager.** Der er intet `timestamp`-felt og ingen `data`-wrapper. Hver blok ligger på øverste niveau i JSON-objektet, som vist ovenfor.

### De 22 webhook-hændelser

De 22 webhook-hændelser med den visningsetiket, du markerer i appen, og den `event`-kode, der sendes i payloaden. `event`-koden er en kort streng, der **ikke** matcher visningsetiketten, så match din modtager på koden, ikke etiketten:

| Visningsnavn (i appen) | `event` kode i payload | Hvad det betyder |
|---|---|---|
| Contact Created | `contactCreated` | En ny kontakt er tilføjet til din konto (manuelt, via import eller via API). |
| Contact Paused | `contact_paused` | En kontaktsamtale er sat på pause (botten stopper med at svare). |
| Contact Resumed | `contact_resumed` | En samtale med en kontakt, der var sat på pause, genoptages. |
| Contact Do Not Disturb | `contact_do_not_disturb_changed` | En kontakts "Forstyr ikke"-indstilling er slået til. |
| Contact Unarchived | `contact_unarchived` | En arkiveret kontakt sender en ny besked, hvilket bringer dem tilbage i din aktive indbakke. |
| New Message | `new_message` | Enhver besked tilføjes til en samtale på en hvilken som helst kanal — både beskeder din kontakt sender til dig, og beskeder din AI eller dit team sender til dem. Dette er den eneste hændelse, der indeholder selve beskedteksten (se [New Message Webhook](#new-message-webhook)). |
| Replies | `replied` | En kontakt svarer på en besked. |
| Reads | `read` | En kontakt læser en besked (på kanaler, der understøtter læsekvitteringer). Indeholder ID'et på den besked, der blev læst — se [Deliveries and Reads Webhook](#deliveries-and-reads-webhook). |
| Deliveries | `delivered` eller `undelivered` | En besked er succesfuldt leveret til en kontakt (`undelivered` hvis leveringen fejler). Indeholder ID'et på beskeden — se [Deliveries and Reads Webhook](#deliveries-and-reads-webhook). |
| Human Alerted | `humanAlerted` | AI-botten vurderer, at den ikke kan håndtere en samtale, og markerer den til menneskelig opmærksomhed. |
| Chat Concluded | `chat_concluded` | AI-botten beslutter, at en samtale er slut (booking foretaget, lead diskvalificeret osv.). |
| Appointment Booked | `booked` | En kontakt booker en aftale gennem bookingsystemet. |
| Credits Spent | `creditsSpent` | Kreditter trækkes fra din konto. |
| Credits Recharged | `creditsRecharged` | Kreditter tilføjes til din konto via automatisk genopfyldning eller manuelt køb. |
| Low Credit Balance | `lowCreditBalance` ved en **Test**-levering, `Low Credit Balance` ved en rigtig levering | En tidlig advarsel om, at din kreditsaldo er faldet under din advarselstærskel (100 kreditter, medmindre du selv har angivet andet). Henvendt til bureauer, hvis underkonti alle bruger fra samme pulje. Den indeholder `balance`, `threshold` og `account_email` i stedet for en kontaktblok, sendes højst én gang hver 24. time, mens saldoen forbliver lav, og genaktiveres så snart saldoen kommer over tærsklen igen. |
| Task Created | `taskCreated` | En opgave er oprettet. |
| Task Updated | `taskUpdated` | En opgave ændres uden at flytte sig til et færdiggørelsesstadie. |
| Task Completed | `taskCompleted` | En opgave flyttes til et stadie, der er konfigureret som et færdiggørelsesstadie. |
| Daily Summary Created | `dailySummaryCreated` | Din daglige opsummeringsrapport genereres. |
| Channel Connected | `channelConnected` | **Sendes ikke endnu — kan vælges, men intet udsender det i dag. Byg ikke mod det.** Beregnet til når en beskedkanal er færdig med at oprette forbindelse. |
| Broadcast Started | `broadcastStarted` | En udsendelse begynder at blive sendt (dens status ændres til Sending). Udløses én gang pr. start, inklusiv når en pauset udsendelse genoptages. Indeholder en `broadcast`-blok i stedet for en kontaktblok: id, navn, kanal, status, forrige status, listen den målretter (`list_id`, `list_name`, `is_smart_list`), `scheduled_at`, `total_contacts`. |
| Broadcast Completed | `broadcastCompleted` | En udsendelse afsluttes (dens status ændres til Sent eller Failed). Samme `broadcast`-blok plus `completed_at` og, når tilgængelig, `completion_summary` (`total_sent`, `permanently_failed`, `unique_replied`, `failure_rate`, `had_errors`). Brug disse to til at forbinde en Smart Broadcast-liste til eksterne værktøjer. |

To koder mere optræder aldrig på den liste, fordi du ikke abonnerer på dem: `contact_tags_updated`, sendt af en webhook-URL indstillet på et individuelt tag, og `summary_generated`, sendt når et chatresumé skrives for et tag i en webhooks `subscribed_to_tags`-liste.

> **Kanal forbundet sendes endnu ikke.** Den optræder på listen over hændelser, men intet udsender den i dag. Byg ikke noget baseret på den.

Tag-baserede og opgave-notifikationer bruger deres egne separate former. Se [Contact Tags Updated](#contact-tags-updated-webhook) og [Task Completed](#task-completed-webhook).

---

## Webhook for oprettet kontakt

Sendes når hændelsen **Kontakt oprettet** udløses (en ny kontakt tilføjes manuelt, via import eller via API).

### Hændelsesnavn

`contactCreated`

### Payload-format

```json
{
  "event": "contactCreated",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null,
    "is_bot_active": true,
    "ad_referral": null
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  }
}
```

| Felt | Beskrivelse |
|---|---|
| `event` | Altid `contactCreated` for denne hændelse. |
| `contact.id` | Det unikke ID for den nye kontakt. |
| `contact.email` / `contact.phone_number` | Kontaktens e-mail og telefonnummer, hvis kendt (begge kan være tomme afhængigt af kanalen). |
| `contact.first_name` / `contact.last_name` | Kontaktens navn, hvis kendt. |
| `contact.human_alerted` / `contact.human_alert_reason` | Hvorvidt kontakten er markeret til menneskelig opmærksomhed, og hvorfor. |
| `contact.is_bot_active` | Hvorvidt AI-botten i øjeblikket er aktiv på denne kontakt. |
| `contact.ad_referral` | Meta Click-to-WhatsApp annonceattribuering, eller `null` — se [Click-to-WhatsApp annonceattribuering](click-to-whatsapp-attribution.md). |
| `campaign` | Den kampagne, kontakten blev oprettet under, eller `null`. |
| `agent` | Den agent, der er tildelt kontakten, eller `null`. |
| `user` | Grundlæggende identitetsoplysninger for den konto, der ejer kontakten. |

> **"Test"-eksemplet og en rigtig hændelse ser lidt forskellige ud.** Testknappen sender pladsholderdata (John Doe, en eksempelkampagne). En rigtig "Kontakt oprettet"-hændelse indeholder kontaktens faktiske detaljer, og nogle felter kan være tomme afhængigt af kanalen.

---

## Webhook for ny besked

Denne webhook udløses hver gang en besked tilføjes til en samtale, på en hvilken som helst kanal. Den dækker begge retninger: beskeder din kontakt sender dig, og beskeder din AI, dit team eller en kampagne sender dem. Det er den eneste webhook, der inkluderer beskedteksten, så det er den, du skal bruge, når du vil spejle samtaler i et eksternt system.

### Hændelsesnavn

`new_message`

### Payload-format

```json
{
  "event": "new_message",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null,
    "is_bot_active": true,
    "ad_referral": null
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<message-id>",
    "body": "Hi, are you open on Saturday?",
    "direction": "inbound",
    "status": "received",
    "created_at": "2026-07-30T17:27:06.000Z",
    "channel": "whatsapp_web"
  }
}
```

| Felt | Beskrivelse |
|---|---|
| `event` | Altid `new_message` for denne hændelse. Bemærk, at dette er den præcise streng, der sendes — det er ikke visningsnavnet "New Message". |
| `contact` | Kontakten, hvis samtale beskeden tilhører. Samme form som i [Contact Created](#contact-created-webhook). |
| `agent` | Agenten, der håndterer samtalen (`id` og `name`), eller `null` hvis ingen agent er involveret. |
| `user` | Grundlæggende identitetsoplysninger for kontoen, der ejer samtalen. |
| `message.id` | Beskedens unikke ID. |
| `message.body` | Beskedteksten. Tom for en besked, der kun indeholder en vedhæftet fil (billede, stemmenote, dokument). |
| `message.direction` | `inbound` for en besked fra kontakten, `outbound` for en sendt af din AI eller af dit team fra indbakken, og `outbound-api` for en sendt af en kampagne, en udsendelse, en skabelon eller API'et. |
| `message.status` | Hvor beskeden er i sin livscyklus: `received` for indgående, og `queued` / `sent` / `delivered` / `read` / `failed` / `undelivered` for udgående. Dette er status på det tidspunkt, hvor beskeden blev oprettet, så en udgående besked ankommer normalt her som `queued` eller `sent` og når `delivered` bagefter — brug **Deliveries** og **Reads**-hændelserne, hvis du har brug for de senere overgange. De indeholder det samme `message.id` som denne blok, så du kan matche overgangen til denne besked (se [Deliveries and Reads Webhook](#deliveries-and-reads-webhook)). |
| `message.created_at` | Hvornår beskeden blev oprettet, i UTC (ISO 8601). |
| `message.channel` | Kanalen beskeden gik igennem, for eksempel `whatsapp`, `whatsapp_web`, `sms`, `instagram`, `messenger`, `telegram`, `email` eller `custom`. |

> **Der er stadig ingen `campaign`-blok i denne payload.** New Message sender `contact`, `agent`, `user` og `message`. `agent`-blokken blev tilføjet den **15. august 2026** og fortæller dig, hvilken agent der håndterer samtalen; hvis du også har brug for kampagnekontekst, kan du slå kontakten op via API'en ved hjælp af `contact.id`.

> **Interne AI-poster udløser ikke denne webhook.** Ved siden af rigtige beskeder holder platformen sine egne bogføringsrækker i en samtale (AI'ens værktøjskald og interne tur-poster). Disse sendes aldrig — du modtager kun beskeder, der rent faktisk blev sendt eller modtaget.

---

## Deliveries and Reads Webhook

Disse to hændelser rapporterer, hvad der skete med en besked, efter den forlod <span data-t="appName">Your AI Connector</span>: **Deliveries** udløses, når en besked når kontakten (eller fejler), og **Reads** udløses, når kontakten åbner den, på de kanaler, der understøtter læsekvitteringer.

Begge indeholder en `message`-blok med ID'et på den besked, hændelsen handler om, så du kan matche opdateringen med den præcise besked, du sendte.

### Hændelsesnavne

`delivered` og `undelivered` for **Deliveries**, `read` for **Reads**.

### Payload-format

```json
{
  "event": "delivered",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "ad_referral": null
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<message-id>",
    "status": "delivered"
  }
}
```

| Felt | Beskrivelse |
|---|---|
| `event` | `delivered` eller `undelivered` for **Deliveries**, `read` for **Reads**. |
| `contact` | Kontakten, som beskeden blev sendt til. |
| `campaign` | Kampagnen, som kontakten tilhører, eller `null`. |
| `agent` | Agenten, der håndterer samtalen, eller `null`. |
| `user` | Grundlæggende identitetsoplysninger for kontoen, der ejer dataene. |
| `message.id` | ID'et på den besked, denne opdatering handler om. Det er den samme værdi, som [send message endpoint](../api/messages.md#send-a-message) returnerer som `messageId`, og det samme `message.id`, som en [New Message](#new-message-webhook)-notifikation indeholder. |
| `message.status` | Den nye status, altid den samme streng som `event` (`delivered`, `undelivered` eller `read`). |

> **Sådan matcher du en opdatering med den besked, du sendte.** Gem det `messageId`, du får tilbage, når du sender en besked via API'et. Når en **Deliveries**- eller **Reads**-notifikation ankommer, skal du slå det gemte ID op mod `message.id` i payloaden — det er din leverings- eller læsekvittering for den præcise besked.

> **Der er ingen beskedtekst her.** `message`-blokken indeholder kun ID'et og status. Abonner på [New Message](#new-message-webhook), hvis du også har brug for selve indholdet.

> **`message`-blokken er kun til stede, når vi ved, hvilken besked det var.** Ved de sjældne opdateringer, vi ikke kan knytte til en gemt besked, udelades blokken helt i stedet for at blive sendt tom — så tjek at `message` eksisterer, før du læser `message.id`.

> **Én notifikation pr. statusændring.** En enkelt udgående besked producerer normalt en `delivered`-notifikation og derefter, på kanaler med læsekvitteringer, en `read`-notifikation. En mislykket afsendelse producerer `undelivered` i stedet.

---

## Appointment Booked Webhook

Udløses når en kontakt booker en aftale. Den udløses på samme måde, uanset om AI'en bookede den under en samtale, du bookede den manuelt, eller den kom ind via API'et.

### Hændelsesnavn

`booked`

### Payload-format

```json
{
  "event": "booked",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith"
  },
  "campaign": {
    "id": "<campaign-id>",
    "name": "AI Receptionist",
    "status": "Live"
  },
  "user": {
    "id": "<account-id>",
    "email": "owner@example.com"
  },
  "appointment": {
    "appointment_id": "<appointment-id>",
    "start_time": "2026-07-20T15:00:00.000Z",
    "end_time": "2026-07-20T15:30:00.000Z",
    "status": "confirmed",
    "room_name": "Room 1",
    "description": "Discovery call",
    "summary": "30 min intro",
    "google_calendar_event_id": null,
    "event": {
      "id": "<service-id>",
      "event_name": "Intro Call",
      "slot_duration": 30,
      "location": "Zoom",
      "meeting_link": "https://...",
      "event_type": "online"
    }
  }
}
```

| Felt | Beskrivelse |
|---|---|
| `event` | Altid `booked` for denne hændelse. |
| `contact` | Personen, der bookede. `email` og `phone_number` kan være tomme afhængigt af kanalen. |
| `appointment.appointment_id` | Det unikke ID for bookingen. |
| `appointment.start_time` / `end_time` | Start og slut på den bookede tid, i UTC (ISO 8601). |
| `appointment.status` | Bookingens nuværende status. |
| `appointment.room_name` | Rummet, bookingen blev foretaget i, hvis det bruges. |
| `appointment.description` / `summary` | Fritekstdetaljer indsamlet ved bookingen. |
| `appointment.google_calendar_event_id` | Google Calendars ID for den synkroniserede begivenhed. Det er ofte `null` i 'Aftale booket'-webhooken, fordi kalenderbegivenheden oprettes i samme øjeblik, som notifikationen sendes — hent aftalen igen via dens `appointment_id` et øjeblik senere, hvis du har brug for det, og forvent en permanent `null` på konti uden tilknyttet Google Calendar. |
| `appointment.event` | Tjenesten, der blev booket: navn, varighed, lokation, mødelink, type. |

> **`google_calendar_event_id` er ofte `null` i denne webhook, og det er normalt.** Google Calendar-hændelsen oprettes i samme øjeblik, som denne notifikation sendes ud, så ID'et er normalt ikke klar endnu. Hent aftalen igen via dens `appointment_id` et øjeblik senere, hvis du har brug for det. Den forbliver `null` permanent, hvis kontoen ikke har en forbundet Google Calendar, så vent ikke på den for evigt.

> **"Test"-knappen inkluderer ikke `appointment`-blokken.** Brug den til at bekræfte, at dit endepunkt svarer, og foretag derefter én rigtig booking for at se den fulde payload.

> **To tilfælde, hvor denne webhook ikke udløses:** aftaler importeret fra en ekstern kalender og bookinger, der kommer ind via Formitable-integrationen.

---

## Webhook for opdaterede kontakt-tags

Udløses, når et tag **anvendes** på en kontakt, og det pågældende tag har en webhook-URL konfigureret på den agent eller kampagne, som kontakten tilhører.

### Hændelsesnavn

`contact_tags_updated`

### Hvornår den udløses

- Et tag anvendes på en kontakt, der har en tildelt agent, en tildelt kampagne eller begge dele.
- Mindst ét af de anvendte tags har en webhook-URL angivet under fanen Tags for den pågældende agent eller kampagne.

Hvis kontakten har begge dele, og kampagnens tags indeholder webhook-URL'er, vinder disse; ellers bruges agentens.

Hvis flere tags med forskellige webhook-URL'er anvendes i samme opdatering, sendes én anmodning pr. URL, hvor hver anmodning kun indeholder de tags, der er knyttet til den pågældende URL.

**Fjernelse af et tag sender aldrig en anmodning.** De fleste peger disse URL'er mod en handling — indsamling af et depositum, booking af en tid, underretning af en medarbejder — så et tag, der fjernes fra en kontakt, blev tidligere brugt til at køre handlingen igen. Det kan det ikke længere. En fjernelse vises stadig i `removed_tags`, når den sker i samme opdatering som en tilføjelse, der går til den samme URL, så en automatisering, der læser begge arrays, bevarer det fulde overblik; hvad den aldrig vil se, er en anmodning forårsaget af en fjernelse alene. (Ændret **12. august 2026**. Før denne dato sendte fjernelser også en anmodning.)

### Payload-format

```json
{
  "event": "contact_tags_updated",
  "contact": {
    "id": "<contact-id>",
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "is_bot_active": true,
    "ad_referral": {
      "ctwa_clid": "ARAbc123...",
      "source_id": "120210000000000",
      "source_type": "ad",
      "source_url": "https://fb.me/xxxx",
      "headline": "Get 20% off today",
      "body": "Message us now to claim your discount",
      "channel": "whatsapp"
    }
  },
  "added_tags": ["qualified-lead"],
  "removed_tags": ["new-lead"],
  "agent": {
    "id": "<agent-id>",
    "name": "Front Desk"
  },
  "user": {
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  }
}
```

| Felt | Beskrivelse |
|---|---|
| `event` | Altid `contact_tags_updated` for denne webhook. |
| `contact.id` | Det unikke ID for kontakten, hvis tags blev ændret. |
| `contact.email` / `contact.phone_number` | Kontaktens e-mail/telefonnummer, hvis det kendes. |
| `contact.first_name` / `contact.last_name` | Kontaktens navn. |
| `contact.human_alerted` | Om kontakten i øjeblikket er markeret til menneskelig opmærksomhed. |
| `contact.is_bot_active` | Om AI-botten i øjeblikket er aktiv i denne kontakts samtale. |
| `contact.ad_referral` | Findes kun, når kontakten første gang kontaktede dig via en Meta Click-to-WhatsApp (CTWA) annonce eller et opslag. `null` ellers. |
| `added_tags` | Array af tag-navne anvendt i denne opdatering. Aldrig tomt – en anvendelse er det, der udløser anmodningen. |
| `removed_tags` | Array af tag-navne fjernet i samme opdatering, hvis nogen. En fjernelse alene sender intet. |
| `agent` | Agenten, der håndterer kontaktens samtale (`id` og `name`), eller `null`, hvis ingen agent er involveret. Tilføjet **15. august 2026**. |
| `user` | Grundlæggende identitetsoplysninger for kontoen, der ejer kontakten. |

### Test af en tag-webhook

Ved siden af webhook-URL-feltet under fanen Tags findes en **Test**-knap. Den sender straks en eksempel-payload til den pågældende URL, så du kan bekræfte, at din automatisering modtager den, før du venter på en rigtig samtale.

Testen sender den samme `contact_tags_updated`-form, som er vist ovenfor, ved hjælp af en pladsholder-kontakt, med det tag du tester i `added_tags` og et tomt `removed_tags`. Det, din automatisering ser i testen, er det, den vil se i produktion.

To ting du skal vide:

- **Gem tagget først.** Testen slår tagget op via dets gemte navn, så et helt nyt tag eller en ikke-gemt omdøbning kan ikke testes endnu. Knappen forbliver grå, indtil navnet på skærmen matcher det gemte.
- **En mislykket test tæller ikke mod din webhook.** Tests bidrager aldrig til den automatiske deaktivering efter gentagne fejl, som beskrevet i [Webhook-pålidelighed](#webhook-reliability).

Hvis testen fejler, fortæller beskeden dig, hvad dit slutpunkt svarede (for eksempel en `404` eller `500`), hvilket normalt er nok til at finde en forkert URL eller et workflow, der ikke er slået til.

---

## Webhook for fuldført opgave

> **Kun til reference.** Opgave-webhooks (som data) er dokumenteret her for udviklere; hændelserne **Opgave oprettet**, **Opgave opdateret** og **Opgave fuldført** kan vælges på listen over standardhændelser i webhook-formularen ligesom enhver anden hændelse — se [Tilgængelige udløserhændelser](#available-trigger-events) og [De 22 webhook-hændelser](#the-22-webhook-events).

Denne payload sendes, når en opgave skifter til et stadie, der er markeret som et fuldførelsesstadie. En opgave, der flyttes mellem stadier, der ikke er fuldførelsesstadier, sender i stedet `taskUpdated`-formatet.

### Hændelsesnavn

`taskCompleted`

### Hvornår den udløses

- En opgave opdateres.
- Dens `stage`-værdi er ændret i forhold til dens tidligere værdi.
- Det nye stadie er konfigureret som et fuldførelsesstadie i kontoens indstillinger for opgavestadier.

### Payload-format

```json
{
  "event": "taskCompleted",
  "contact": {
    "email": "jane@example.com",
    "phone_number": "+15551234567",
    "first_name": "Jane",
    "last_name": "Smith",
    "human_alerted": false,
    "human_alert_reason": null
  },
  "user": {
    "email": "owner@example.com",
    "first_name": "Alex",
    "last_name": "Doe"
  },
  "message": {
    "id": "<task-id>",
    "title": "Follow up with Jane",
    "description": "Confirm pricing and send proposal",
    "type": "follow_up",
    "priority": "high",
    "stage": "<stage-id>",
    "due_date": "2026-01-20T15:00:00Z",
    "source": "ai",
    "source_detail": "<source-detail>",
    "campaign_id": "<campaign-id>",
    "linked_human_alert": "<human-alert-id>",
    "tags": ["qualified-lead"],
    "notes": "Customer requested a callback"
  }
}
```

| Felt | Beskrivelse |
|---|---|
| `event` | Altid `taskCompleted` for denne webhook. Den samme payload-form sendes som `taskUpdated`, når en opgave ændres uden at gå ind i et fuldførelsesstadie. |
| `contact` | Kontakten tilknyttet opgaven, hvis nogen. `null` når ikke tilknyttet. |
| `contact.human_alert_reason` | Årsagen til, at kontakten blev markeret til menneskelig opmærksomhed, hvis relevant. |
| `user` | Grundlæggende identitetsoplysninger for den konto, der ejer opgaven. |
| `message.id` | Det unikke ID for opgaven. |
| `message.title` / `description` | Opgavens titel og beskrivelse. |
| `message.type` | Opgavetypen (for eksempel `follow_up`, `call`, `custom`). |
| `message.priority` | Opgavens prioritet (`low`, `medium`, `high`). |
| `message.stage` | ID'et for det stadie, opgaven nu befinder sig i. |
| `message.due_date` | Opgavens forfaldsdato, hvis angivet. |
| `message.source` | Hvad der oprettede opgaven (`ai`, `manual`, `api`). |
| `message.source_detail` | Yderligere detaljer om kilden. |
| `message.campaign_id` | ID'et for den tilknyttede kampagne eller `null`. |
| `message.linked_human_alert` | ID'et for den tilknyttede menneskelige advarsel, hvis nogen. |
| `message.tags` | Tags anvendt på opgaven. |
| `message.notes` | Noter i fritekst om opgaven. |

---

## Slå en webhook fra (eller slet den)

Hver webhook har en tænd/sluk-knap direkte på sin række. Hvis du slår en webhook **fra**, stopper den med at modtage hændelser, men alt, hvad du har konfigureret, bevares — URL'en, hændelserne og eventuelle signaturhemmeligheder. Slå den til igen, og den fortsætter, hvor den slap; intet af det, der skete, mens den var slået fra, leveres efterfølgende.

Brug den, når du ønsker, at leveringer skal stoppe i et stykke tid: dit endpoint er ved at blive genopbygget, du debugger en støjende integration, eller du sætter en automatisering på pause.

**Sletning** af en webhook (papirkurvsikonet på dens række) fjerner den permanent, inklusive dens signaturhemmelighed. Hvis du kun ønsker at stoppe leveringer, skal du i stedet slå den fra — sletning er til, når du er helt færdig med slutpunktet.

> **Dette er ikke det samme som at en webhook slås automatisk fra.** Hvis vi deaktiverer din webhook efter gentagne fejl (se [Webhook-pålidelighed](#webhook-reliability)), vil kontakten ovenfor ikke aktivere den igen. Når dit endpoint er rettet, skal du redigere webhooken og gemme den med en ændret URL (enhver ændring af URL'en genaktiverer den), eller kalde [genaktiverings-endpointet](../api/webhooks.md) via API'et — eller spørg supporten, så aktiverer vi den for dig.

---

## Signerede payloads (Verificering af, at en webhook rent faktisk kommer fra os)

Enhver, der får kendskab til din webhook-URL, kan sende en falsk anmodning til den. Hvis du reagerer automatisk på webhooks — f.eks. ved opdatering af fakturering eller oprettelse af CRM-poster — giver aktivering af **signering** dig mulighed for at verificere, at hver anmodning rent faktisk kommer fra os.

Signering er **valgfri og deaktiveret som standard**, og du aktiverer den pr. webhook fra den pågældende webhooks redigeringsvisning (åbn rækken for et gemt webhook).

### Aktivering af signering

1. Åbn webhooken (Indstillinger → Integrationer → Webhooks → klik på rækken for din webhook).
2. I sektionen **Signeringshemmelighed** skal du klikke på **Generer**.
3. Kopiér hemmeligheden (den starter med `whsec_`) og gem den i dit modtagende system. Behandl den som en adgangskode.

Du kan altid vende tilbage og afsløre, kopiere, rotere eller deaktivere hemmeligheden fra dette samme panel.

### Hvad vi sender

Når signering er aktiveret, indeholder hver levering for den webhook disse to ekstra HTTP-headere:

| Header | Betydning |
|---|---|
| `X-Webhook-Signature` | Signaturen, i formen `v1=<hex>`. |
| `X-Webhook-Timestamp` | Hvornår vi sendte den, som et Unix-tidsstempel i sekunder. |

Disse tre er med i **hver** levering, uanset om de er signerede eller ej:

| Header | Betydning |
|---|---|
| `X-Webhook-Delivery` | Et unikt ID for denne hændelse. Forbliver det samme på tværs af forsøg, så det er det, du deduplikerer ud fra. |
| `X-Webhook-Attempt` | Hvilket forsøg dette er (`1` er det første forsøg). |
| `X-Webhook-Event` | Hændelsesnavnet, så du kan dirigere uden at læse indholdet. |

### Sådan verificerer du

Signaturen er en HMAC-SHA256 af strengen `<timestamp>.<raw request body>`, hvor din signeringshemmelighed bruges som nøgle.

**Verificer mod den rå anmodningstekst — de nøjagtige bytes, du modtog.** Hvis dit framework parser JSON-koden og serialiserer den igen før kontrol, kan bytes ændre sig, og signaturen vil ikke matche.

Node.js-eksempel:

```js
const crypto = require("crypto");

function verify(rawBody, headers, secret) {
  const timestamp = headers["x-webhook-timestamp"];
  const signature = headers["x-webhook-signature"]; // "v1=<hex>"

  // Reject anything older than 5 minutes so a captured request can't be replayed later.
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const expected = crypto.createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");

  return crypto.timingSafeEqual(Buffer.from(signature.replace("v1=", "")), Buffer.from(expected));
}
```

Python-eksempel:

```python
import hashlib, hmac, time

def verify(raw_body: bytes, headers, secret: str) -> bool:
    timestamp = headers["X-Webhook-Timestamp"]
    signature = headers["X-Webhook-Signature"].replace("v1=", "")

    # Reject anything older than 5 minutes so a captured request can't be replayed later.
    if abs(time.time() - int(timestamp)) > 300:
        return False

    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()

    return hmac.compare_digest(signature, expected)
```

> **Sammenlign signaturer med en timing-sikker funktion** (`timingSafeEqual` / `compare_digest`), ikke `==`. Det koster intet og undgår en subtil klasse af angreb.

### Roter hemmeligheden

Klik på **Roter** for at udskifte hemmeligheden. Skiftet sker øjeblikkeligt: den næste levering signeres kun med den nye hemmelighed. Hvis dit endpoint er aktivt, bør du acceptere **både** den gamle og den nye hemmelighed i et par minutter, mens du udruller den nye.

Hvis du slår signering fra, stopper det blot afsendelsen af signatur-headere.

---

## Genforsøg af fejlede leveringer

Som standard genforsøges en levering, der fejler, ikke — hvis dit system er nede i det øjeblik, går den begivenhed tabt.

Slå **Forsøg mislykkede leveringer igen** til på en webhook (i opret/rediger-formularen), så bliver vi ved med at prøve:

| Forsøg | Hvornår |
|---|---|
| 1 | Med det samme |
| 2 | 1 minut senere |
| 3 | 5 minutter senere |
| 4 | 30 minutter senere |
| 5 | 2 timer senere |

Det strækker sig over cirka **2 timer og 40 minutter**, så en webhook kan overleve et vedligeholdelsesvindue eller et kort nedbrud hos dig.

**Hvad genforsøges:** midlertidige problemer — hvis din server returnerer en 5xx-fejl, en timeout eller en forbindelsesfejl.

**Hvad der ikke gør:** hvis dit endpoint selv afviser anmodningen (enhver 4xx-fejl), forsøger vi ikke igen — at sende den identiske anmodning igen ville kun resultere i den samme afvisning.

**Hvilke hændelser forsøges igen:** tag-webhooks (`contact_tags_updated`), de tre opgavehændelser og det daglige resumé. Resten sendes én gang, så for dem har kontakten intet at handle på. Hver hændelse bærer stadig `X-Webhook-Delivery`, så én deduplikeringsregel dækker dem alle.

> **Slå kun genforsøg til, hvis dit endpoint er idempotent.** Genforsøg betyder, at den samme hændelse kan ankomme mere end én gang. Brug `X-Webhook-Delivery`-headeren til at genkende en gentagelse: den forbliver den samme på tværs af alle forsøg for én hændelse, så du sikkert kan ignorere et ID, du allerede har håndteret.

Genforsøg interagerer med den automatiske deaktivering efter gentagne fejl (se [Webhook-pålidelighed](#webhook-reliability)) på den måde, du ønsker: fejl-tælleren tæller en **hel levering**, først efter at hvert genforsøg er opbrugt – ikke hvert enkelt forsøg.

---

## Webhook-pålidelighed

- <span data-t="appName">Your AI Connector</span> sender webhooks over en sikker forbindelse (HTTPS). Sørg for, at den webadresse, du angiver, bruger HTTPS.
- Hvis dit system returnerer en fejl, betragtes leveringen som mislykket.
- Overvåg dit modtagende systems oppetid for at undgå at gå glip af begivenheder.
- For kritiske arbejdsgange bør du slå [Forsøg mislykkede leveringer igen](#retrying-failed-deliveries) til og overveje en fallback-mekanisme.

> **Webhooks slås automatisk fra efter gentagne fejl.** Hvis din webhook-URL fejler gentagne gange (ca. 5 fejl i træk, eller 3 i træk ved konfigurationsfejl), stopper <span data-t="appName">Your AI Connector</span> automatisk med at sende hændelser til den URL. For at aktivere den igen, når dit endpoint er sundt: rediger webhooken og gem den med en ændret URL (enhver ændring af URL'en genaktiverer den), eller brug [genaktiverings-endpointet](../api/webhooks.md) via API'et — det er ikke nok at gemme den igen med den samme URL. Supporten kan også genaktivere den for dig.

---

## Fejlfinding

| Problem | Løsning |
|---|---|
| Webhook udløses ikke | Kontrollér først, at webhooken ikke er slået **fra** på sin række. Bekræft derefter, at de korrekte begivenheder er valgt, og at din URL er tilgængelig fra internettet. |
| Testbegivenhed virker, men rigtige begivenheder gør ikke | Sørg for, at den specifikke begivenhedstype er aktiveret. Hvis du forventede en anmodning, når et tag tilføjes, skal du bemærke, at `subscribed_to_tags` ikke begrænser en webhooks begivenheder til et tag – det indsnævrer kun, hvilke tags der producerer en notifikation om samtaleresumé. For at få en anmodning, når et specifikt tag tilføjes, skal du indstille en webhook-URL på det tag under fanen **Tags** for agenten (eller kampagnen) – se [Webhook for opdaterede kontakt-tags](#contact-tags-updated-webhook). |
| Intet ankommer i n8n / Make / Zapier | Du bruger sandsynligvis platformens **Test-URL**, som kun lytter efter en enkelt begivenhed lige efter at have klikket på "Lyt efter testbegivenhed." For live-begivenheder skal du gemme **Produktions-URL'en** og skifte workflowet til **Aktiv**. |
| Modtager duplikerede begivenheder | Tjek for flere webhooks, der peger på den samme URL. Hvis **Genforsøg mislykkede leveringer** er slået til, forventes en gentagelse, hver gang dit endepunkt accepterede en begivenhed, men ikke svarede i tide – deduplikér på `X-Webhook-Delivery`. |
| Signaturtjek fejler altid | Næsten altid fordi brødteksten blev re-serialiseret før tjek. Verificér mod den **rå** anmodningskrop, signér `<timestamp>.<body>`, og bekræft, at du bruger den aktuelle hemmelighed, hvis du for nylig har roteret den. |
| Genforsøg sker ikke | Genforsøg er slået fra, medmindre de er aktiveret på den specifikke webhook. Vi genforsøger ikke 4xx-svar. |
| `campaign`-blokken er altid `null` | Forventet hvis din konto bruger agenter: kontakter er tilknyttet en agent frem for en kampagne. Læs `agent`-blokken i stedet – se [Webhook-dataformat](#webhook-data-format). |
| Data er tomme eller misdannede | Verificér, at dit modtagende system accepterer JSON. Tjek dine serverlogfiler for parseringsfejl. |
| Webhook-URL returnerer fejl | Test din URL med et værktøj som Postman eller [webhook.site](https://webhook.site). |
| Webhook stoppede helt med at udløses efter et nedbrud | Gentagne fejl deaktiverer automatisk en webhook. At gemme igen genaktiverer den ikke – ret dit endepunkt, og kontakt derefter support. |
| Gem eller Test giver en tilladelsesfejl | Du skal have "rediger"-tilladelse til integrationer. Bed kontoens ejer om at give den. |
| En webhooks `subscribed_to_tags`-liste kom tilbage tom | `subscribed_to_tags` begrænser ikke en webhooks begivenheder til et tag – det indsnævrer kun, hvilke tags der producerer en notifikation om samtaleresumé. Redigering fra webhook-formularen rydder ikke længere den liste (rettet 21. juli 2026). Hvis en webhook mistede sin liste før den dato, skal du indstille `subscribed_to_tags` igen via [Webhooks API](../api/webhooks.md) – se [Tag-baserede webhook-udløsere](#tag-based-webhook-triggers). |

---

## Næste skridt

- [GoHighLevel-integration](ghl-integration.md) — brug webhooks til at integrere <span data-t="appName">Your AI Connector</span> med GHL.
- [API-adgang](api-access.md) — kombiner webhooks med API'et for kraftfuld automatisering.
- [Brug af tags til at mærke kontakter](../get-started/creating-tags.md) — opsæt tags, der udløser dine webhooks.
