> ## 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.

# PDF receipt via DOCUMENT header

> Send a WhatsApp Utility template with a receipt PDF attached as a document header.

This guide shows the Option B receipt pattern: the WhatsApp message includes a PDF document header and body variables describing the receipt.

Use this pattern when the customer should receive the receipt document directly in WhatsApp instead of opening a receipt page.

## Before you start

You need:

* A connected WhatsApp channel in Switchbord.
* An approved Utility template with a `DOCUMENT` header, for example `payment_receipt_document`.
* A public HTTPS PDF URL. Meta must be able to fetch it.
* A stable upstream event id for idempotency.

<Warning>
  The document URL must be HTTPS and reachable by Meta. Do not use internal-only URLs, localhost, expiring URLs that expire before dispatch, or URLs containing reusable secrets.
</Warning>

## Template shape

A typical document receipt template has a document header and a body like:

```text theme={null}
Ciao {{1}}, la ricevuta {{2}} è allegata a questo messaggio.
```

The document header receives:

```json theme={null}
{
  "link": "https://cdn.example.com/receipts/R-1001.pdf",
  "filename": "R-1001.pdf"
}
```

## Direct API send

```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-pdf-R-1001" \
  -d '{
    "templateName": "payment_receipt_document",
    "templateLocale": "it",
    "recipient": {
      "phoneE164": "+393331234567",
      "externalId": "traveller-123",
      "name": "Giulia Rossi"
    },
    "variables": {
      "header": {
        "document": {
          "link": "https://cdn.example.com/receipts/R-1001.pdf",
          "filename": "R-1001.pdf"
        }
      },
      "body": {
        "1": "Giulia",
        "2": "R-1001"
      }
    },
    "metadata": {
      "source": "booking-system",
      "eventType": "payment.receipt.pdf_ready"
    }
  }'
```

Expected response:

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

## Inbound webhook builder

To map an external payment event into this template:

1. Open **Settings → Integrations → Webhooks & API**.
2. Create a new inbound webhook.
3. Select the approved `payment_receipt_document` Utility template.
4. Map the fields:

| Template field    | Source mode             | Example source                      |
| ----------------- | ----------------------- | ----------------------------------- |
| Recipient phone   | Payload path            | `customer.phone`                    |
| External ID       | Payload path            | `receipt.id`                        |
| PDF document link | Payload path            | `receipt.pdf`                       |
| PDF filename      | Literal or payload path | `receipt.pdf` or `receipt.filename` |
| Body `{{1}}`      | Payload path            | `customer.first_name`               |
| Body `{{2}}`      | Payload path            | `receipt.number`                    |

1. Paste a sample payload and run the dry-run preview.
2. Create the webhook. New configs stay disabled and dry-run by default until live promotion is supported.

Sample payload:

```json theme={null}
{
  "customer": {
    "phone": "+393331234567",
    "first_name": "Giulia"
  },
  "receipt": {
    "id": "payment-receipt-pdf-R-1001",
    "number": "R-1001",
    "filename": "R-1001.pdf",
    "pdf": "https://cdn.example.com/receipts/R-1001.pdf"
  }
}
```

## Named body variables

Switchbord's inbound webhook mapper and internal transactional compiler support Meta named body parameters and compile them into `parameter_name` entries. The public `POST /api/v1/template-sends` route currently accepts positional body variables only, so direct API callers should use numeric body keys or an array.

## Validation

Switchbord validates the document header before queueing:

* `link` must be a valid HTTPS URL.
* `filename`, when supplied, must be non-empty.
* Required body variables must resolve to non-empty strings.
* The selected template must be approved Utility.
* The idempotency key must be stable for retries.

## Troubleshooting

| Symptom                            | Check                                                                                |
| ---------------------------------- | ------------------------------------------------------------------------------------ |
| `400 invalid_media_link`           | The document link is not valid HTTPS or cannot be parsed as a URL.                   |
| `400 invalid_document_filename`    | A filename was supplied but resolved to an empty string.                             |
| `400 missing_template_name`        | The webhook mapping did not resolve a template, or no template was selected.         |
| `401 invalid_signature`            | Webhook request was not signed with the one-time webhook secret.                     |
| Meta delivery fails after queueing | Confirm the PDF URL is still reachable by Meta and returns the correct content type. |

## Related reference

* [Transactional template sends](/api-reference/transactional-template-sends)
* [Inbound webhooks](/api-reference/inbound-webhooks)
* [Template rules](/whatsapp/template-rules)
