This is the most common use of a utility template: sending the invoice. A Meta template can carry a header with a document, an image or a video, and that file is chosen on every send — the approved template fixes the TYPE, you supply the file.
How to send it. Like any template (POST /v1/messages with type: "template"), except the components array carries a header component first, with the file:
{ "type": "header", "parameters": [ { "type": "document", "document": { "link": "https://…/A-1042.pdf", "filename": "Invoice A-1042.pdf" } } ] }
Where the file comes from: a link of yours. Meta accepts link (a public https URL Meta downloads) or id (a media id). Connect stores no files and has no upload endpoint, so the only ids that exist are those of files you RECEIVED — to send an invoice of your own, host it and send the link. Same rule as "Send media", for the same reason: we don't keep content.
⚠ The parameter type is dictated by the TEMPLATE, not the file. If Meta approved the header as DOCUMENT, the parameter goes as document even if the file is a JPG. Sending image on a DOCUMENT template is rejected by Meta.
⚠ filename is documents only (it's the name the recipient sees). On image and video Meta rejects it.
🔴 What you CAN'T do: CREATE a media-header template from Connect. Only text headers can be built here. If you send a header.format of image/document/video to POST /v1/templates you get 400 TEMPLATE_PRECHECK_FAILED with code TPL_HEADER_FORMAT_UNSUPPORTED — we don't create it half-way and we don't tell you it worked. The path is: create it in Meta Business Manager (which does accept media headers) and then POST /v1/templates/sync — Connect reads it correctly, lists it, notifies you when its status changes, and sends it as above.
curl -X POST https://api.waiaconnect.com/v1/messages \
-H "Authorization: Bearer wc_live_YOUR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"connectionId":"conn_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX","to":"5493511234567","type":"template","template":{"name":"envio_factura","language":"es","components":[{"type":"header","parameters":[{"type":"document","document":{"link":"https://your-server.example/invoices/A-1042.pdf","filename":"Factura A-1042.pdf"}}]},{"type":"body","parameters":[{"type":"text","text":"María"}]}]}}'
# The header component goes FIRST and its type is the one the APPROVED TEMPLATE
# declares (document | image | video) — NOT the file's mime type.
# image: {"type":"image","image":{"link":"https://…/photo.jpg"}} (no filename)
# by media id instead of a link: {"document":{"id":"1234567890"}}
# ⚠ You cannot CREATE a media-header template from Connect (only TEXT headers).
# Create it in Meta Business Manager, then POST /v1/templates/sync.How to tell whether a template needs a file: GET /v1/templates returns header: { format: "DOCUMENT" } (or IMAGE/VIDEO). In the panel they're marked with 📎.
If you forget the file we tell you BEFORE Meta does: 422 TEMPLATE_HEADER_MEDIA_REQUIRED, with details.example = the exact component that's missing. Meta answers an opaque 132000 instead.
And if it gets through anyway (a template we haven't synced yet), the message fails on the first attempt with lastErrorCode = TEMPLATE_PARAM_MISMATCH — we don't retry a payload that cannot work five times.
What the link needs: https, pointing straight at the file (no login, no landing page), with the right Content-Type. ⚠ A Google Drive or Dropbox "share" link returns an HTML page: Meta downloads that and rejects the send. Meta's limits: document 100 MB, image 5 MB, video 16 MB.
Meta caches your link for 10 minutes: if you change the file behind the same URL, add a different ?v=….