---
title: "Webhook: pubblica messaggi in un canale mssgs"
description: "Invia un messaggio o una card in un canale mssgs da CI, monitoraggio o uno script con una richiesta HTTP. Formati, file, firma, errori, limiti e GitHub."
canonical: https://docs.mss.gs/it/webhooks
language: it
---

# Pubblica messaggi con un webhook

Un webhook è un URL che pubblica nella tua community. Mandagli del JSON da qualsiasi cosa sappia fare una richiesta HTTP, come la CI, il monitoraggio, un cron job o uno script, e il messaggio compare nel canale.

## Cosa puoi fare

- **Pubblica testo o una card** Testo semplice, oppure una card con titolo, colore, markdown, campi e immagini.

- **Allega file** Fino a cinque file per messaggio: log, report, screenshot.

- **Aggiungi pulsanti** Link, oppure pulsanti che cambiano la card o raggiungono il tuo servizio.

- **Cambialo dopo** La risposta contiene una callback URL per aggiornare o eliminare il messaggio.

Nell'app

#### Build #1847 riuscita

Una richiesta dalla CI, una card in #deploys. Il nome in alto è quello che hai dato al webhook.

- [Per iniziare](#quick-start)

- [Cosa puoi inviare](#format)

- [File](#attachments)

- [Firma](#signing)

- [Risposte ed errori](#responses)

- [Limiti](#limits)

- [GitHub, UniFi, App Store](#special)

## Per iniziare

### Crea il webhook

Nell’app desktop apri **Gestisci il server → Webhook** della tua community, crea un webhook, scegli i canali in cui può pubblicare e copia l’URL per un canale. Ha questa forma:

```url
https://mss.gs/api/v1/webhook/{webhook_guid}/{token}/{channel_guid}
```

### Invia un messaggio

Firma il JSON con il segreto del webhook e invialo in POST. Un webhook creato nell’app desktop ne ha sempre uno: copialo da **Segreto del webhook** nelle impostazioni del webhook.

```bash
BODY='{"content": "Build #1847 passed on main"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //')

curl -X POST "$MSSGS_WEBHOOK_URL" \
  -H "Content-Type: application/json" \
  -H "X-Mssgs-Signature: sha256=$SIG" \
  -d "$BODY"
```

### Leggi la risposta

La risposta ti dà l’id del messaggio e una callback_url per cambiare il messaggio in seguito.

```json
{
  "success": true,
  "message_id": "aZZ1a2b-...",
  "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-...",
  "stream_url": "https://mss.gs/api/v1/instant/6b1e...c0?token=a1b2c3d4-..."
}
```

## Cosa puoi inviare

Un messaggio è la forma breve (testo con un titolo e un colore) oppure una card completa, e in entrambi i casi può avere pulsanti e file. Il nome in cima alla card è sempre il nome del webhook. Nelle impostazioni del webhook decidi anche se può pubblicare immagini e menzionare persone.

### Forma breve

Basta per la maggior parte degli avvisi.

```json
{
  "content": "Server backup completed at 03:00 UTC",
  "color": "green",
  "title": "Backup Bot"
}
```

| Campo | Tipo | Cosa fa |
| --- | --- | --- |
| content | string | Il testo del messaggio. Obbligatorio, a meno che tu non invii una card o dei file. |
| color | string | blue (predefinito), green , orange , red , yellow o purple . |
| title | string | Un titolo sopra il testo. Se manca, è il nome del webhook. |

### Una card completa

Invia un message_container per una card con titolo linkato, sottotitolo, markdown, campi e immagini. Tramite un webhook una card accetta type , color , title , title_url , sub_title , description , fields , avatar_url , image_url , image_base64 , images e i campi del loader. La pillola di stato, il badge, le statistiche diff e il ragionamento ripiegato sono per le risposte ai comandi. Ogni campo è descritto in [card dei messaggi](https://docs.mss.gs/it/bots).

```json
{
  "message_container": {
    "type": "embed_message",
    "color": "green",
    "title": "Build #1847 passed",
    "title_url": "https://ci.example.com/builds/1847",
    "description": "All 212 tests green on **main**.",
    "fields": [
      { "field": "Duration", "value": "2m 34s" },
      { "field": "Commit", "value": "1a2b3c4" }
    ]
  }
}
```

#### Build #1847 riuscita

### Pulsanti

Aggiungi un array actions per mettere dei pulsanti sotto il messaggio. Come funzionano è spiegato in [pulsanti](https://docs.mss.gs/it/buttons).

## File

Pubblica file veri con un messaggio: un log, un report, uno screenshot. Vengono mostrati come qualsiasi altro allegato, come riga da scaricare oppure inline per immagini, video e audio. Un messaggio con soli file va bene: ometti content e la card.

```json
{
  "message_container": {
    "color": "orange",
    "title": "Log dump: ios",
    "description": "DMs stopped arriving after switching networks"
  },
  "attachments": [
    {
      "name": "mssgs-logs-20260803-141205.log",
      "content_base64": "MjAyNi0wOC0wMyAxNDoxMjowNSBbV1NdIGNvbm5lY3RlZAo=",
      "mime_type": "text/plain"
    }
  ]
}
```

| Campo | Tipo | Cosa fa |
| --- | --- | --- |
| name | string | Il nome con cui il file viene scaricato. Obbligatorio. Un percorso viene ridotto alla sua ultima parte. |
| content_base64 | string | I byte del file in base64, grezzi o come URI data: . mssgs salva il file e sul messaggio tiene solo un link. |
| mime_type | string | Il content type di content_base64 . Predefinito: text/plain . |
| url | string | Un file già ospitato su mssgs: un percorso /static/... o un URL https://mss.gs/... . |

| Limite | Valore |
| --- | --- |
| File per messaggio | **5** |
| Dimensione per file, dopo la decodifica | **8 MB** |
| Nome del file | 200 caratteri |
| Richiesta intera | Circa 10 MB. Il base64 rende un file più grande di un terzo, quindi un singolo file oltre i 7 MB circa non ci sta. |

### Perché url accetta solo indirizzi mssgs

L’URL di un webhook finisce spesso incollato in altre dashboard. Se trapela, non deve permettere a qualcuno di far scaricare all’app di ogni membro un file da un server scelto da lui. Se il tuo file si trova altrove, invialo come content_base64 e lo ospita mssgs.

### Un caricamento fallito non fa fallire il messaggio

I file vengono controllati subito ma caricati dopo. Se un caricamento fallisce, quel file viene tralasciato e il resto del messaggio viene comunque pubblicato, senza errori: meglio perdere il file che perdere il report. Se un file è importante, controlla che sia arrivato.

### Un file dalla riga di comando

```bash
BODY='{"attachments":[{"name":"report.csv","content_base64":"'"$(base64 < report.csv | tr -d '\n')"'","mime_type":"text/csv"}]}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$MSSGS_WEBHOOK_SECRET" | sed 's/^.* //')

printf '%s' "$BODY" | curl -sS -X POST "$MSSGS_WEBHOOK_URL" \
  -H 'Content-Type: application/json' \
  -H "X-Mssgs-Signature: sha256=$SIG" \
  --data-binary @-
```

## Firmare le richieste

Un webhook con un segreto accetta solo le richieste che dimostrano di conoscerlo, e un webhook creato nell’app desktop ne ha sempre uno (**Segreto del webhook** nelle sue impostazioni). Firma il body grezzo della richiesta con HMAC-SHA256 usando il segreto e invia il digest esadecimale in minuscolo nell’header X-Mssgs-Signature , come sha256=<hex> .

```javascript
import crypto from 'node:crypto';

const body = JSON.stringify({ content: 'Deploy finished' });
const signature = crypto.createHmac('sha256', process.env.MSSGS_WEBHOOK_SECRET)
  .update(body)
  .digest('hex');

await fetch(process.env.MSSGS_WEBHOOK_URL, {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-Mssgs-Signature': `sha256=${signature}`
  },
  body
});
```

Viene accettato anche l’header X-Hub-Signature-256 di GitHub, quindi un webhook GitHub con lo stesso segreto funziona così com’è. La firma non ha un timestamp, quindi non impedisce che una richiesta intercettata venga inviata di nuovo: il segreto che conta resta l’URL.

## Risposte ed errori

Un messaggio pubblicato torna indietro con il suo id e una callback_url per aggiornarlo o eliminarlo per 30 minuti.

```json
{
  "success": true,
  "message_id": "aZZ1a2b-...",
  "callback_url": "https://mss.gs/api/v1/trigger-callback/8f14e45f-...",
  "stream_url": "https://mss.gs/api/v1/instant/6b1e...c0?token=a1b2c3d4-..."
}
```

```http
HTTP/1.1 200 OK
Content-Type: application/json

{ "error": "ATTACHMENT_TOO_LARGE" }
```

```javascript
const res = await fetch(webhookUrl, { method: 'POST', headers, body });
const reply = await res.json().catch(() => null);

// A rejected payload still comes back as 200: read the body.
if (!res.ok || (reply && reply.error)) {
  throw new Error(`webhook rejected: ${reply?.error ?? res.status}`);
}
```

Quando il messaggio ha dei pulsanti, la risposta contiene anche uno stream_url : uno stream live delle risposte, delle reazioni e delle pressioni dei pulsanti su quel messaggio, aperto per 10 minuti, oppure per un’ora se invii "sse_event_extended_timeout": true . Vedi [aggiornamenti live](https://docs.mss.gs/it/live-updates).

### Status code

| Status | Quando |
| --- | --- |
| 401 | Il webhook ha un segreto e la firma manca o è sbagliata. |
| 403 | Questo webhook non può pubblicare in quel canale. |
| 404 | Non c’è nessun webhook a questo URL. |
| 413 | La richiesta è troppo grande. |
| 429 | Troppe richieste. Rallenta e riprova. |
| 502 | Non è stato possibile consegnare il messaggio. Riprova. |

### Codici di errore

| Codice | Significato |
| --- | --- |
| MISSING_CONTENT | Niente da pubblicare: né testo, né card, né file. |
| INVALID_MESSAGE_CONTAINER | message_container non è un oggetto. |
| INVALID_MESSAGE_CONTAINER_TYPE | Il tipo della card non è né embed_message né system_message . |
| MISSING_MESSAGE_CONTAINER_DESCRIPTION | Una card ha bisogno di una descrizione, a meno che non sia un loader. |
| MISSING_MESSAGE_CONTAINER_LOADER_TEXT | Una card con loader ha bisogno di loader_text . |
| INVALID_WEBHOOK_BINDING | Questo webhook non può pubblicare in quel canale. |
| INVALID_SIGNATURE | L’header della firma manca o è sbagliato. |
| REQUEST_BODY_TOO_LARGE | La richiesta supera il limite di dimensione. |
| PUBLISH_FAILED | Non è stato possibile consegnare il messaggio. |
| INVALID_ACTIONS_FORMAT , INVALID_ACTION_MISSING_FIELDS , DUPLICATE_ACTION_ID , INVALID_TRIGGERS_FORMAT , INVALID_TRIGGER_MISSING_ACTION , INVALID_TRIGGER_ACTION_NOT_ALLOWED | C’è qualcosa che non va in un pulsante. Vedi [pulsanti](https://docs.mss.gs/it/buttons). |

### Errori dei file

| Codice | Significato |
| --- | --- |
| INVALID_ATTACHMENTS_FORMAT | attachments non è una lista, oppure una voce non è un oggetto. |
| TOO_MANY_ATTACHMENTS | Più di cinque file. |
| MISSING_ATTACHMENT_NAME | Un file non ha un nome. |
| INVALID_ATTACHMENT_NAME | Il nome si riduce a niente di utilizzabile, come .. . |
| MISSING_ATTACHMENT_SOURCE | Né url né content_base64 . |
| AMBIGUOUS_ATTACHMENT_SOURCE | Sia url sia content_base64 . |
| INVALID_ATTACHMENT_BASE64 | Il base64 non si decodifica. |
| ATTACHMENT_TOO_LARGE | Un file supera gli 8 MB dopo la decodifica. |
| INVALID_ATTACHMENT_URL | L’ url non è un indirizzo mssgs. |

## Limiti

| Limite | Valore |
| --- | --- |
| Dimensione della richiesta | Circa 10 MB |
| File per messaggio | 5, fino a 8 MB ciascuno |
| Descrizione della card | Fino a 50.000 byte. Oltre i 1.000 byte, i membri vedono l’inizio e un pulsante **Mostra di più**. |
| Aggiornare il messaggio in seguito | 30 minuti, tramite callback_url |
| Stream live di un messaggio con pulsanti | 10 minuti, oppure un’ora su richiesta |

Le richieste hanno un rate limit. Quando ricevi un 429 , aspetta prima di inviare di nuovo, e raggruppa in un solo messaggio gli avvisi che arrivano a raffica.

## GitHub, UniFi e App Store Connect

Punta uno di questi servizi all’URL di un webhook e mssgs lo riconosce e pubblica una card fatta apposta, senza payload da scrivere. Vedi [integrazioni](https://mss.gs/it/integrations). Questi rispondono con {"success": true} e senza callback URL.

| Fonte | Riconosciuta da | Cosa pubblica |
| --- | --- | --- |
| GitHub | L’header x-github-event | Push, pull request e revisioni, issue e commenti, branch e tag, release. Una raffica di modifiche a una stessa issue o pull request viene raccolta in una sola card. |
| UniFi Protect | Lo user agent protect-alarm-manager | Il campanello che suona, il movimento, e persone, veicoli o pacchi rilevati dalle tue telecamere. |
| App Store Connect | Il body della sua notifica o l’header x-apple-signature | Le notifiche di App Store Connect. |

## Continua a costruire
