Webhooks

Un webhook de intrare permite unui alt sistem să posteze într-un canal prin trimiterea unui JSON către o URL secretă. Un webhook de ieșire face exact opusul: trimite către URL-ul dvs. mesajele care încep cu un cuvânt de declanșare sau pe care utilizatorii le selectează în meniul mesajului, și postează răspunsul pe care îl primiți.

Unde gestionați webhooks

Deschideți avatarul din colțul din dreapta sus, apoi Integrări. Paginile de integrări ale comunității curente listează Webhooks de intrare și Webhook de ieșire. Fiecare webhook aparține unei singure comunități.

By default, community admins and system admins can create webhooks. A system admin can give the right to other roles in the permission settings of the System Console. A system admin can also turn each kind off in System Console › Integrations › Integration Management: Enable Incoming Webhooks and Enable Outgoing Webhooks are both on by default.

A channel with messages from a CI bot and from GitHub, shown as cards with fields, pipeline stages and a button
Mesaje de integrare desenate ca carduri: câmpuri, etape de pipeline și un buton de acțiune.

Crearea unui webhook de primire

  1. În Integrări, selectați Webhooks de intrare, apoi Adăugați Webhook de intrare.
  2. Completați un Titlu și o Descriere: acestea apar doar pe paginile de integrări.
  3. Alegeți Channel către care se trimit mesajele în mod implicit. Pentru un canal privat, trebuie să fiți membru al acestuia.
  4. Bifați Blocați acest canal dacă trimițătorii nu trebuie să poată posta în altă parte.
  5. Opțional, setați un Utilizator și o adresă URL pentru Poză de profil pentru mesajele sale (a se vedea Nume și pictogramă).
  6. Selectați Salvează. Copiați adresa URL afișată: https://chat.example.com/hooks/<key>.
URL-ul este singurul secret: oricine îl deține poate posta în canal. Păstrați-l departe de depozitele publice și ștergeți webhook-ul dacă este scurs.

Cu API: POST /api/v4/hooks/incoming cu {"channel_id", "display_name", "description", "username", "icon_url", "channel_locked"}; id din răspuns este cheia. Din linia de comandă: amctl webhook create-incoming --channel <channel id> --user <user> --display-name "CI".

Trimiterea unui mesaj către un webhook de primire

curl -X POST https://chat.example.com/hooks/xgh5ycrx1jf7mbs9w8z4c8e7ho \
  -H 'Content-Type: application/json' \
  -d '{"text": "Deploy of **api 2.4.0** finished :white_check_mark:"}'

Serverul răspunde cu 200 și corpul ok. Acceptă și application/x-www-form-urlencoded cu JSON într-un câmp payload, așa cum fac webhooks-urile Slack, astfel încât instrumentele create pentru Slack funcționează de obicei neschimbate.

CâmpSemnificație
textMesajul, în format Markdown. Obligatoriu, cu excepția cazului în care există attachments. Un text mai lung decât limita de mesaj a serverului este împărțit în mai multe mesaje.
channelAlt canal din comunitatea webhook-ului, după nume (ops-alerts sau #ops-alerts), sau @username pentru un mesaj direct de la proprietarul webhook-ului. Este refuzat dacă webhook-ul este blocat pe canalul său. Vechiul nume town-square ajunge încă la canalul implicit al comunității, numit acum general.
username, icon_url, icon_emojiNumele și imaginea de profil de afișat, dacă serverul permite suprascrierea.
attachmentsAtașamentele mesajului, afișate sub formă de carduri (mai jos).
propsProprietăți suplimentare stocate pe mesaj, pentru aplicațiile care le citesc.
typeUn tip de mesaj personalizat, de exemplu custom_poll, pentru o aplicație care îl afișează. Tipurile care încep cu system_ sunt refuzate.
root_idID-ul primului mesaj dintr-un fir de discuție, pentru a răspunde în acel fir.
priorityPrioritatea mesajului, de exemplu {"priority": "urgent"}.
silenttrue trimite mesajul fără notificări push.

Fiecare mesaj postat de un webhook are o etichetă BOT lângă numele său, chiar dacă este afișat sub numele creatorului, pentru a fi deosebit de mesajele persoanelor reale. Mesajele de webhook nu declanșează niciodată webhooks de ieșire.

Nume și pictogramă

Un webhook postează în numele persoanei care l-a creat, cu excepția cazului în care serverul permite suprascrieri. Două setări din Consola de sistem › Integrări › Managementul integrării, ambele dezactivate în mod implicit, modifică acest lucru:

  • Activați integrațiile pentru a suprascrie numele de utilizator (ServiceSettings.EnablePostUsernameOverride): este afișat Utilizator al webhook-ului sau username din cerere; în absența oricărui element, numele este webhook.
  • Activați integrațiile pentru a înlocui pictogramele de imagini de profil (ServiceSettings.EnablePostIconOverride): este afișată Poza de profil a webhook-ului, sau icon_url sau icon_emoji din cerere.

O valoare din cerere are prioritate față de cea salvată pe webhook.

Atașamente

Atașamentele adaugă conținut structurat sub text. Ele urmează formatul de atașament de mesaj de la Slack:

{
  "text": "Build failed on `main`",
  "attachments": [{
    "fallback": "main #1902 failed",
    "color": "#d24b4e",
    "author_name": "GitHub Actions",
    "author_icon": "https://chat.example.com/static/ci.png",
    "title": "main #1902 failed",
    "title_link": "https://ci.example.com/runs/1902",
    "text": "Commit `0f4d8e2` by Jonas Weber",
    "fields": [
      {"title": "Branch", "value": "zephyr-3.7", "short": true},
      {"title": "Duration", "value": "3m 40s", "short": true}
    ],
    "footer": "Lumen CI",
    "ts": 1760000000
  }]
}
CâmpSemnificație
fallbackText simplu pentru locurile care nu pot afișa cardul, cum ar fi notificările.
colorBara de culoare: o culoare hexazecimală, sau good, warning, danger.
pretextText deasupra cardului.
author_name, author_link, author_iconO linie de antet mică.
title, title_linkTitlul cardului, opțional un link.
textCorpul cardului, în format Markdown.
fieldsO listă de {"title", "value", "short"}; câmpurile short sunt așezate unul lângă altul.
image_url, thumb_urlO imagine mare de jos, sau una mică lateral.
footer, footer_icon, tsO linie de subsol și un moment în timp (secunde Unix).
actionsButoane și meniuri: vezi Mesaje interactive.

Carduri: etape și grafice

Antimatter adaugă două câmpuri la atașamente, afișate de interfața implicită:

  • stages: pașii unui pipeline, afișate ca pastile, până la 20. Fiecare este {"name", "status"}, cu un status de passed, failed, running, pending, skipped sau canceled.
  • chart: un grafic liniar mic al valorilor recente, {"values": [2 to 200 numbers], "threshold": number, "label": "…"}. Pragul este desenat ca o linie întreruptă, pentru limita unei alerte.
{
  "attachments": [{
    "color": "danger",
    "title": "main #1902 failed",
    "stages": [
      {"name": "build", "status": "failed"},
      {"name": "unit", "status": "skipped"},
      {"name": "publish", "status": "skipped"}
    ]
  }, {
    "color": "warning",
    "title": "API latency above 400 ms",
    "chart": {"values": [210, 230, 260, 390, 450, 470], "threshold": 400, "label": "p95 latency, ms"}
  }]
}

Interfața clasică și alți clienți ignoră aceste două câmpuri, așa că puneți esențialul și în text sau fields.

Creați un webhook de ieșire

Un webhook de ieșire monitorizează canalele Public ale unei comunități. Trimite un mesaj către URL-ul dvs. fie atunci când primul cuvânt al mesajului se potrivește cu unul dintre cuvintele sale de declanșare, fie atunci când cineva îl selectează în meniul mesajului (o acțiune de mesaj).

  1. În Integrări, selectați Webhook de ieșire, apoi Adăugați Webhook de ieșire.
  2. Completați Titlul și Descrierea.
  3. Selectați Tip-conținut al cererii: application/x-www-form-urlencoded sau application/json.
  4. Alegeți un Canal, introduceți Cuvinte de declanșare (câte una pe linie), sau ambele. Cu un canal și fără cuvinte de declanșare, fiecare mesaj din acel canal este trimis. Cu ambele, mesajul trebuie să se potrivească cu ambele.
  5. Sub Declanșează cînd, alegeți Primul cuvânt se potrivește exact cu un cuvânt de declanșare, Primul cuvânt începe cu un cuvânt de declanșare sau Din meniul mesajului. Cu Din meniul mesajului, cuvintele de declanșare dispar, Canal este opțional (fără unul, acțiunea este oferită în fiecare canal public al comunității), iar Titlu este obligatoriu: acesta este numele acțiunii în meniu.
  6. Introduceți Adrese URL cu inversare (câte unul pe linie). Fiecare adresă URL primește fiecare mesaj care se potrivește.
  7. Setați opțional Utilizator și Poză de profil folosite pentru răspunsuri. Pentru o acțiune din meniul mesajului, câmpul Icon înlocuiește Poză de profil: URL-ul unei imagini .png sau .jpg sau, în interfața implicită a Antimatter, o imagine încărcată. Meniul o afișează în gri; fără una, acțiunea primește o pictogramă neutru.
  8. Alegeți Salvează și copiați tokenul afișat. Serviciul dumneavoastră îl folosește pentru a verifica dacă cererile provin de la serverul dumneavoastră.

Prin API: POST /api/v4/hooks/outgoing cu {"team_id", "channel_id", "trigger_words", "trigger_when", "callback_urls", "content_type", "display_name"} (trigger_when: 0 pentru potrivire exactă, 1 pentru „începe cu”, 2 pentru „din meniul mesajului”). Un webhook cu trigger_when 2 nu necesită cuvinte de declanșare și cere un display_name. Încărcați pictograma sa cu POST /api/v4/hooks/outgoing/{hook_id}/icon (multipart, câmp image: PNG, JPEG sau GIF, stocată ca PNG de 128 px); icon_url va indica apoi către GET /api/v4/hooks/outgoing/{hook_id}/icon.

Dacă serviciul dumneavoastră se află pe o rețea privată, un administrator de sistem trebuie să permită adresa acestuia în Permiteți conexiunile interne de neîncrederi la (ServiceSettings.AllowedUntrustedInternalConnections). În caz contrar, serverul nu apelează adrese private.

Cererea de ieșire

Antimatter trimite un POST cu aceste câmpuri, ca JSON sau form-encoded, în funcție de tipul de conținut:

{
  "token": "6kd1ofo5ojr5zgu5ipfipybgnc",
  "team_id": "…",
  "team_domain": "lumen-labs",
  "channel_id": "…",
  "channel_name": "ops-alerts",
  "timestamp": 1760010000000,
  "user_id": "…",
  "user_name": "priya",
  "post_id": "…",
  "text": "deploy api 2.4.0",
  "trigger_word": "deploy",
  "file_ids": ""
}

Comparați token cu tokenul webhook-ului înainte de a face orice. În versiunea form-encoded, timestamp este în secunde, nu în milisecunde. Serverul așteaptă răspunsul dumneavoastră atât timp cât permite Timp de așteptare pentru cererile de integrare (30 de secunde implicit, ServiceSettings.OutgoingIntegrationRequestsTimeout).

Răspundeți la un webhook de ieșire

Pentru a trimite un răspuns, răspundeți cu JSON. Pentru a nu trimite nimic, răspundeți cu un corp gol.

{
  "text": "Deploying **api 2.4.0** to staging…",
  "response_type": "comment",
  "username": "deploy-bot",
  "icon_url": "https://chat.example.com/static/deploy.png"
}
  • text și attachments: răspunsul. Fără niciunul dintre ele, nu se publică nimic.
  • response_type: comment publică răspunsul în firul de discuție al mesajului care a declanșat webhook-ul; în caz contrar, acesta este publicat în canal.
  • username, icon_url: afișate când serverul permite suprascrieri; în caz contrar, se folosesc valorile proprii ale webhook-ului.
  • props, type, priority: la fel ca pentru webhook-urile de intrare.

Răspunsul este publicat de către creatorul webhook-ului, sub numele suprascris, dacă există. Pentru orice răspuns mai lung decât unul scurt, răspundeți imediat și publicați ulterior cu un webhook de intrare sau cu API-ul.

Acțiuni de mesaj

O acțiune de mesaj este un webhook de ieșire cu Declanșează cînd setat la Din meniul mesajului. Nu se declanșează niciodată la mesajele publicate. În schimb, utilizatorii o văd în meniul unui mesaj: Acțiuni mesaj (⋯) › Mai multe actiuni, sub antetul Integrări, împreună cu pictograma sa. Interfața clasică nu afișează acțiunile de mesaj. Selectarea acesteia trimite acel mesaj unic către URL-urile de callback, iar un scurt anunț indică Trimis către numele acțiunii sau afișează ephemeral_text specific.

  • Unde apare: în canalul webhook-ului sau, în lipsa unui canal, în toate canalele publice ale comunității. Doar canalele publice au acțiuni de mesaj.
  • Oaspeții primesc doar acțiunile asociate cu un canal în care se află, nu și cele la nivel de comunitate.
  • Canale arhivate și doar pentru citire: mesajul poate fi totuși trimis. Arhivarea unui canal șterge webhook-urile asociate cu acesta, astfel încât un canal arhivat păstrează doar acțiunile la nivel de comunitate. Un răspuns pe care persoana nu l-ar putea publica acolo este afișat doar acesteia.
  • Limita de rată: fiecare persoană poate executa 10 acțiuni de mesaj pe minut, după o serie inițială de 5. În caz contrar, serverul răspunde cu 429.
  • Rețele private: la fel ca în cazul celorlalte webhook-uri de ieșire, adresele interne trebuie să fie permise în Permiteți conexiunile interne de neîncrederi la.

Cererea

Plasa este trimisă ca JSON sau codificată ca formular, în funcție de tipul de conținut al webhook-ului:

{
  "token": "6kd1ofo5ojr5zgu5ipfipybgnc",
  "trigger": "message_action",
  "team_id": "…",
  "team_domain": "lumen-labs",
  "channel_id": "…",
  "channel_name": "ops-alerts",
  "timestamp": 1760010000000,
  "user_id": "…",
  "user_name": "priya",
  "post_id": "…",
  "post_root_id": "",
  "post_create_at": 1760009000000,
  "post_user_id": "…",
  "post_user_name": "jonas",
  "permalink": "https://chat.example.com/lumen-labs/pl/…",
  "text": "The staging database is full again",
  "files": [{"id": "…", "name": "df.txt", "link": "https://chat.example.com/api/v4/files/…"}],
  "priority": "",
  "requested_ack": false,
  "burn_on_read": false
}
  • user_id și user_name sunt ale persoanei care a selectat acțiunea; post_user_id și post_user_name sunt ale autorului mesajului.
  • Doar acel mesaj este trimis, niciodată restul firului de discuție.
  • files listează fișierele mesajului doar dacă persoana care a selectat acțiunea le poate descărca. Descărcarea unui link necesită o sesiune sau un token, la fel ca orice fișier din API.
  • Un mesaj de tip „burn-on-read” este trimis fără text și fără fișiere, cu burn_on_read setat la true.
  • În formatul form-encoded, fișierele apar ca câmpuri repetate file_id, file_name și file_link, în aceeași ordine.

Răspunsul

Răspundeți la fel ca pentru orice webhook de ieșire (a se vedea Răspuns la un webhook de ieșire): text sau attachments publică un răspuns în canal, iar "response_type": "comment" îl publică în firul de discuție al mesajului. Puteți răspunde și cu ephemeral_text (limitat la 300 de caractere): acesta este afișat doar persoanei care a selectat acțiunea, în notificare. Un corp gol nu publică nimic.

{"ephemeral_text": "Ticket OPS-412 created"}

Cu API-ul

  • GET /api/v4/channels/{channel_id}/message_actions: acțiunile pe care le puteți selecta într-un canal, cu id, display_name, description și icon_url. Nu se returnează nici tokenuri, nici URL-uri de callback.
  • POST /api/v4/posts/{post_id}/message_actions/{hook_id}: execută o acțiune pe un mesaj pe care îl puteți citi. Răspunde cu {"ephemeral_text"}.

Când un webhook nu funcționează

  • 501 de la URL-ul hook-ului: webhook-urile de intrare sunt dezactivate pe server.
  • 400 "Failed to decode the payload…": JSON-ul este invalid, sau câmpul de formular nu se numește payload. "No text specified." înseamnă că cererea nu are nici text, nici attachments.
  • 403: webhook-ul este blocat pe un alt canal, sau proprietarul acestuia nu mai poate citi canalul.
  • Un webhook de ieșire nu se declanșează niciodată: canalul este privat, declanșatorul nu este primul cuvânt, mesajul a venit de la un webhook sau webhook-ul este configurat să se declanșeze Din meniul mesajului.
  • O acțiune de mesaj nu apare în meniu: canalul este privat, acțiunea este legată de alt canal, persoana este oaspete și acțiunea nu are canal asociat, sau webhook-urile de ieșire sunt dezactivate.
  • 404 la executarea unei acțiuni de mesaj: acțiunea nu există sau nu acoperă canalul mesajului pentru acea persoană. 429: persoana a executat mai mult de 10 acțiuni într-un minut. 502: niciunul dintre URL-urile de callback nu a putut fi accesat (motivul se află în jurnal).
  • Jurnale: cu Activați depanarea Webhook activat (LogSettings.EnableWebhookDebugging) și nivelul de jurnalizare setat pe DEBUG, serverul înregistrează în jurnal încărcăturile cererilor primite eșuate. Apelurile externe eșuate sunt înregistrate ca Outgoing Webhook POST failed.