Guides
Template Media Headers
How to send approved Cloud templates that carry a native WhatsApp document (PDF), image, or video — including per-customer files from your ERP or storage — without putting a download URL in the message text.
1. Choose the right pattern
| Customer should receive | Template header | API field at send time | Typical use |
|---|---|---|---|
| Native PDF / document bubble | DOCUMENT |
header_media_url or header_media_file |
Invoices, contracts, statements, tickets |
| Native image | IMAGE |
header_media_url or header_media_file |
Receipts, banners, product shots |
| Native video | VIDEO |
header_media_url or header_media_file |
Short explainers, demos |
| Clickable URL in the text | None / text header | body_variables containing the URL |
Hosted download pages — see Dynamic Invoice Link |
| Same sample media every time | DOCUMENT / IMAGE / VIDEO |
Omit media fields (uses template sample) | Static announcements only |
2. How DOCUMENT delivery works
- Create and approve a UTILITY (or other allowed) template in the dashboard with header format DOCUMENT. Upload any valid sample PDF for Meta review.
- At send time, pass a public HTTPS URL to the customer-specific file via
header_media_url, or upload the bytes via multipartheader_media_file. - Washeej downloads the file from that URL once, uploads it to Meta for the sending number, and sends the template with Meta’s media id.
- Meta delivers a WhatsApp document. The end user sees a file, not the raw URL. If Washeej cannot download the file, the URL itself goes to Meta and Meta downloads it.
header_media_url is a fetch address for Washeej’s servers (and, as a fallback, Meta’s). Do not confuse it with putting a link inside body_variables.
3. Media URL requirements
- Must be HTTPS and reachable from the public internet (not
localhost, not private VPC-only hosts). - Must return HTTP 200 on
GETwith the binary body (query-string download endpoints are fine if they return the file). - Preferred
Content-Type:application/pdffor documents, matching image/video MIME for other headers. - Meta document size limit: 100 MB (images 5 MB, videos 16 MB).
- Prefer a path or
Content-Dispositionfilename ending in.pdfso WhatsApp shows a clear file name. - Signed / short-lived URLs are OK if they remain valid long enough for Meta to fetch at send time.
- Auth walls, HTML login pages, or HTML error bodies will fail Meta media download (often surfaced as media upload errors).
- Serve a ready file, fast. Meta downloads the URL itself, shortly after the send, and gives up if your server is slow (webhook
message.failed, code131053"did not respond back in time"). Generate the PDF before you call the API and serve it as a static file with a fullContent-Length; do not build it inside the download request. - Use a unique URL per file (for example a token in the path) so a fetch never reuses an older file.
- When you retry a send (timeout, 5xx), send the same
Idempotency-Key: a new key is a new message, and the customer receives the document twice.
GET (User-Agent Washeej-MediaCheck/1.0, 10 s timeout, redirects not followed, up to 16 MB), checks its real type against the header (PDF / JPEG / PNG / MP4 …), uploads it to Meta for your number and sends the media id, so Meta never has to reach your server. The uploaded id is reused for the same URL and the same content. When the download fails (timeout, error status, redirect, wrong type, larger file) the URL goes to Meta as before, after one HEAD size check. Links to private, loopback or reserved addresses are rejected. If Meta then fails that URL with 131053, Washeej uploads the file and sends the same message once more (same message id, no second message); message.failed is sent only if that also fails.
message.failed webhooks with Meta’s code.
4. Scenario A — Dynamic PDF via public URL (JSON)
Best when your system already stores each document behind a stable or signed HTTPS link.
curl -X POST "https://staging-mobile.washeej.com/v1/templates/send" \
-H "client-id: YOUR_CLIENT_ID" \
-H "client-secret: YOUR_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{
"template_id": "YOUR_TEMPLATE_ID",
"mobile_code": "966",
"mobile": "500000000",
"whatsapp_account_id": YOUR_CLOUD_ACCOUNT_ID,
"header_media_url": "https://files.example.com/docs/INV-1001.pdf",
"body_variables": ["Ahmed", "INV-1001"]
}'
body_variables only if the approved template body contains {{1}}, {{2}}, … Placeholders. A fully static body needs no body variables.
5. Scenario B — Upload the PDF at send time (multipart)
Best when the file lives only on your app server and you do not want a public URL.
curl -X POST "https://staging-mobile.washeej.com/v1/templates/send" \
-H "client-id: YOUR_CLIENT_ID" \
-H "client-secret: YOUR_CLIENT_SECRET" \
-F "template_id=YOUR_TEMPLATE_ID" \
-F "mobile_code=966" \
-F "mobile=500000000" \
-F "whatsapp_account_id=YOUR_CLOUD_ACCOUNT_ID" \
-F "header_media_file=@/path/to/invoice.pdf;type=application/pdf" \
-F "body_variables[]=Ahmed" \
-F "body_variables[]=INV-1001"
Accepted file fields: header_media_file or media_file. Washeej stores the upload temporarily and passes a public fetch URL to Meta.
6. Scenario C — DOCUMENT header + dynamic body text
Use when the customer should get both a PDF bubble and personalized text (name, invoice number, amount, …).
- Header format: DOCUMENT (sample PDF for Meta review).
- Body example:
Hello {{1}}, invoice {{2}} is attached. Amount due: {{3}} {{4}}. - Send with
header_media_url(or file upload) and orderedbody_variables.
7. Scenario D — IMAGE or VIDEO headers
Same API fields as documents. Only the approved template header_format changes.
{
"template_id": "YOUR_TEMPLATE_ID",
"mobile_code": "966",
"mobile": "500000000",
"whatsapp_account_id": YOUR_CLOUD_ACCOUNT_ID,
"header_media_url": "https://cdn.example.com/receipts/1001.jpg",
"body_variables": ["Order 1001"]
}
- IMAGE — JPEG/PNG, max 5 MB.
- VIDEO — MP4, max 16 MB.
- DOCUMENT — PDF preferred, max 100 MB.
8. Scenario E — URL in the message text (not a file)
If the product requirement is a link inside the chat text, do not use a DOCUMENT header.
Create a text template and pass the URL in body_variables.
Full walkthrough:
Dynamic Invoice Link.
9. Scenario F — Free-form document inside the 24-hour window
Within 24 hours of the customer’s last inbound message you may send a regular document with
POST /messages
(session message). Outside that window, WhatsApp requires an approved template —
use this guide’s DOCUMENT header pattern.
10. Discover template IDs and header format
- Call
GET /templates(scopetemplates:read). - Use either the Washeej numeric
idor Metawhatsapp_template_idastemplate_idwhen sending. - Confirm
header_formatisDOCUMENT,IMAGE, orVIDEObefore relying onheader_media_url. - Send only from a Cloud API channel (
whatsapp_account_id). Device/QR channels do not support Meta templates.
11. Legacy Cloud API
The same fields work on the legacy path (existing integrations):
curl -X POST "https://staging-mobile.washeej.com/external-api/inbox/send-template-message" \
-H "client-id: YOUR_CLIENT_ID" \
-H "client-secret: YOUR_CLIENT_SECRET" \
-H "Content-Type: application/json" \
-d '{
"template_id": "YOUR_TEMPLATE_ID",
"mobile_code": "966",
"mobile": "500000000",
"whatsapp_account_id": YOUR_CLOUD_ACCOUNT_ID,
"header_media_url": "https://files.example.com/docs/INV-1001.pdf"
}'
New integrations should prefer POST /v1/templates/send.
12. Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| Customer sees a URL in text, not a file | URL was put in body_variables on a text template |
Use a DOCUMENT-header template + header_media_url |
| Media / upload errors from Meta | URL not publicly downloadable, HTML error page, wrong MIME, or oversized file | Verify public GET returns binary PDF/image/video under Meta limits |
message.failed code 131053: "did not respond back in time" |
Your server answered Meta's download too slowly (often a PDF generated inside the download request) | Pre-generate the file and serve it statically with Content-Length; send again |
| Error: "Template header media URL must be a public http(s) link." | The link points at a private, loopback or reserved address, or uses another scheme | Use a public https:// URL reachable by Meta |
| Same sample PDF every time | header_media_url / file omitted |
Pass the customer-specific media on every send |
capability_error |
Sending from Device/QR channel | Use a Cloud account whatsapp_account_id |
not_found for template |
Wrong id / not approved / wrong account | Re-check GET /templates for that Cloud number |
Validation error on header_media_url |
Not a valid absolute URL | Use full https://… value |