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

# Link alla ricevuta di pagamento tramite bottone URL

> Configura un sistema esterno di pagamento o prenotazione per inviare link alle ricevute WhatsApp tramite Switchbord.

Questa guida mostra il pattern di ricevuta dell'Opzione A: il corpo del modello WhatsApp contiene i dettagli della ricevuta e un bottone URL dinamico apre la pagina della ricevuta ospitata.

Usa questo pattern quando il tuo sistema esterno ospita già le pagine delle ricevute e vuoi un messaggio Utility piccolo e previsto in WhatsApp.

## Prima di iniziare

Ti serve:

* Un canale WhatsApp collegato in Switchbord.
* Una chiave API Switchbord per l'area di lavoro, se chiami direttamente `POST /api/v1/template-sends`.
* Un modello Utility approvato con un bottone URL, ad esempio `payment_receipt_link`.
* Una pagina di ricevuta pubblica HTTPS come `https://pay.example.com/receipts/R-1001`.

<Warning>
  Non usare questo flusso per messaggi promozionali. I modelli Utility devono essere legati a eventi previsti dal cliente come pagamento, rata, prenotazione, rimborso o disponibilità di un documento.
</Warning>

## Struttura del modello

Un tipico modello di link alla ricevuta contiene variabili nel corpo e un bottone URL:

```text theme={null}
Ciao {{1}}, abbiamo ricevuto il pagamento {{2}} per la ricevuta {{3}}.
```

```text theme={null}
Button URL: https://pay.example.com/receipts/{{1}}
```

La variabile del bottone è il suffisso dinamico. Se l'URL base è `https://pay.example.com/receipts/`, invia solo `R-1001` come variabile.

## Invio diretto tramite API

```bash theme={null}
curl -X POST https://api.switchbord.ai/api/v1/template-sends \
  -H "Authorization: Bearer $SWITCHBORD_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: payment-receipt-R-1001" \
  -d '{
    "templateName": "payment_receipt_link",
    "templateLocale": "it",
    "recipient": {
      "phoneE164": "+393331234567",
      "externalId": "traveller-123",
      "name": "Giulia Rossi"
    },
    "variables": {
      "body": {
        "1": "Giulia",
        "2": "€ 240,00",
        "3": "R-1001"
      },
      "buttons": {
        "url": [
          { "index": 0, "suffix": "R-1001" }
        ]
      }
    },
    "metadata": {
      "source": "booking-system",
      "eventType": "payment.receipt.created"
    }
  }'
```

Risposta prevista:

```json theme={null}
{
  "data": {
    "contactId": "contact_123",
    "conversationId": "conversation_123",
    "messageId": "message_123",
    "clientMessageId": "payment-receipt-R-1001",
    "status": "queued",
    "reused": false,
    "idempotent": true
  }
}
```

## Builder per webhook in entrata

Se il sistema esterno può chiamare un webhook ma non può archiviare una chiave API Switchbord, configura invece un webhook in entrata per l'area di lavoro:

1. Apri **Impostazioni → Integrazioni → Webhook e API**.
2. Crea un nuovo webhook in entrata.
3. Seleziona il modello Utility approvato `payment_receipt_link`.
4. Mappa i campi richiesti:

| Campo del modello         | Modalità sorgente    | Sorgente di esempio   |
| ------------------------- | -------------------- | --------------------- |
| Telefono destinatario     | Percorso nel payload | `customer.phone`      |
| ID esterno                | Percorso nel payload | `receipt.id`          |
| Corpo `{{1}}`             | Percorso nel payload | `customer.first_name` |
| Corpo `{{2}}`             | Percorso nel payload | `receipt.amount`      |
| Corpo `{{3}}`             | Percorso nel payload | `receipt.number`      |
| Variabile del bottone URL | Percorso nel payload | `receipt.number`      |

1. Incolla un payload di esempio ed esegui l'anteprima dry-run.
2. Crea il webhook. L'endpoint resta disabilitato/dry-run finché un futuro flusso di promozione verificato tramite run-log non abilita l'esecuzione live.

Payload di esempio:

```json theme={null}
{
  "customer": {
    "phone": "+393331234567",
    "first_name": "Giulia"
  },
  "receipt": {
    "id": "payment-receipt-R-1001",
    "number": "R-1001",
    "amount": "€ 240,00",
    "link": "https://pay.example.com/receipts/R-1001"
  }
}
```

## Firma delle richieste webhook in entrata

Le richieste webhook usano firme HMAC con timestamp. Il segreto viene mostrato solo una volta alla creazione del webhook.

```ts theme={null}
import { createHash, createHmac } from "node:crypto";

const rawBody = JSON.stringify(payload);
const timestamp = Math.floor(Date.now() / 1000);
const secretHash = createHash("sha256").update(webhookSecret).digest("hex");
const digest = createHmac("sha256", secretHash)
  .update(`${timestamp}.${rawBody}`)
  .digest("hex");

await fetch(webhookUrl, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Switchbord-Signature": `t=${timestamp},v1=${digest}`,
    "Idempotency-Key": payload.receipt.id
  },
  body: rawBody
});
```

Non inviare mai il segreto webhook grezzo come header, parametro query o campo JSON.

## Checklist di rollout

* Esegui l'anteprima dry-run nel browser e verifica la richiesta mappata.
* Non aspettarti ancora run log firmati sull'endpoint per le configurazioni create da Impostazioni; restano disabilitate finché la promozione live non viene rilasciata.
* Conferma che il modello sia Utility approvato nella stessa area di lavoro.
* Usa chiavi di idempotenza stabili basate sull'id dell'evento a monte.
* Mantieni gli URL delle ricevute solo HTTPS ed evita di incorporare token privati a lunga durata.

## Risoluzione dei problemi

| Sintomo                             | Verifica                                                                                                                                                |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `404 webhook_not_found_or_disabled` | Le configurazioni create da Impostazioni sono disabilitate oggi; usa l'anteprima nel browser o l'API diretta finché la promozione non viene rilasciata. |
| Futuro `401 missing_timestamp`      | `X-Switchbord-Signature` deve includere `t=<secondi unix>`.                                                                                             |
| Futuro `401 expired_timestamp`      | L'orologio del mittente differisce di più di cinque minuti.                                                                                             |
| Futuro `401 invalid_signature`      | Firma il corpo esatto della richiesta grezza, non una copia riserializzata.                                                                             |
| `400 template_not_approved_utility` | Seleziona un modello Utility approvato nella stessa area di lavoro.                                                                                     |
| `400 missing_button_url_variable`   | Mappa il suffisso del bottone URL e assicurati che risolva a una stringa non vuota.                                                                     |
| Invii duplicati                     | Usa una `Idempotency-Key` stabile per ogni evento di ricevuta.                                                                                          |
