Meta Template Library
Meta maintains a catalog of ready-made WhatsApp message templates — the Template Library. Every entry has already been written and reviewed by Meta, in many languages. When you adopt one without changing the wording, it is created in your WhatsApp Business Account already APPROVED, so you can send it immediately instead of waiting out a review.
This is the fastest path from "channel connected" to "first template sent", and it is what powers the one-click template flow in the SendSeven app.
| Library template (unchanged) | Template you write yourself | |
|---|---|---|
| Approval | Instant — created as APPROVED | Review, usually minutes, up to 24 hours |
| Wording | Fixed by Meta | Yours |
| Categories | UTILITY, AUTHENTICATION | UTILITY, MARKETING, AUTHENTICATION |
| Buttons | Meta's, optionally re-pointed at your URLs / phone numbers | Yours |
Changing the body, header or footer of a library entry makes it your template: it goes through Meta's normal review like any other new template. You can still rename it and point its buttons at your own destinations while keeping instant approval — those are not content changes.
Required Scopes
| Endpoint | Scopes |
|---|---|
GET /whatsapp-templates/library | channels:read |
POST /whatsapp-templates/library/adopt | channels:admin or messages:create |
messages:create is accepted for adoption on purpose. The main use case is an agent who has no approved template and needs one to open a conversation — gating a Meta-curated, pre-approved action behind channel administration would break exactly the flow it exists for.
Browse the Library
GET /api/v1/whatsapp-templates/library
Required Scope: channels:read
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
channel_id | string | — | Required. WhatsApp channel whose WABA credentials are used to read the catalog |
language | string | — | Meta language code, e.g. en_US. Omit for all languages |
search | string | — | Free-text search across name, body, topic and use case |
topic | string | — | e.g. PAYMENTS |
usecase | string | — | e.g. LOW_BALANCE_WARNING |
industry | string | — | e.g. FINANCIAL_SERVICES |
name | string | — | Exact library template name |
limit | integer | 100 | Max entries to return (1–500) |
curl -X GET "https://api.sendseven.com/api/v1/whatsapp-templates/library?channel_id=71a1351f-4d6a-4444-9c6b-1cc8d63d7408&language=en_US&search=delivery&limit=20" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json"
Response
{
"items": [
{
"id": "1055577921234567",
"name": "delivery_update_1",
"language": "en_US",
"category": "UTILITY",
"topic": "ORDER_MANAGEMENT",
"usecase": "DELIVERY_UPDATE",
"industry": ["E_COMMERCE"],
"header": null,
"body": "Your order {{1}} is on its way and should arrive by {{2}}.",
"footer": null,
"body_params": ["ORD-5678", "Feb 15"],
"body_param_types": ["order_id", "date"],
"buttons": [
{
"type": "URL",
"text": "Track order",
"url": "https://www.example.com/track",
"phone_number": null,
"otp_type": null
}
],
"already_added": false,
"requires_input": true
}
],
"total": 34,
"facets": {
"languages": ["en_US", "de_DE", "es_ES"],
"topics": ["ORDER_MANAGEMENT", "PAYMENTS"],
"usecases": ["DELIVERY_UPDATE", "PAYMENT_DUE"],
"industries": ["E_COMMERCE", "FINANCIAL_SERVICES"]
},
"language": "en_US",
"stale": false,
"warning": null
}
total is the number of matches found before limit was applied. facets are derived from the matched result set (Meta has no facets endpoint), so they are exactly the filter values that would return something.
Two fields are added by SendSeven, not by Meta:
| Field | Meaning |
|---|---|
already_added | This tenant already has a template with the same name and language on this channel. Adopting again is a no-op (see Idempotency) |
requires_input | At least one button needs a value only you can supply — a link URL or a phone number. Meta's catalog ships placeholder destinations (example.com, sample numbers) for those, so you must pass button_inputs when adopting. false means the entry can be adopted with no extra input |
Caching, staleness and 429s
Meta rate-limits its template endpoints aggressively, while the library catalog is global and near-static. SendSeven therefore caches it server-side for 12 hours, and keeps a longer-lived copy (14 days) purely as a fallback.
If Meta is unreachable or rate-limits the call and a fallback copy exists, the request still succeeds — with stale: true and a human-readable warning:
{
"items": ["..."],
"total": 34,
"stale": true,
"warning": "Meta is rate-limiting template requests, so this list may be slightly out of date."
}
Treat that as a soft hint ("may be out of date"), not an error. Only when there is no cached copy at all does the endpoint fail:
| Status | Cause |
|---|---|
400 | Channel is not a usable WhatsApp channel (missing WABA or token) |
429 | Meta rate-limited us and nothing was cached |
503 | Meta transiently unreachable and nothing was cached (retryable) |
502 | Meta returned a non-retryable error |
Adopt a Library Template
POST /api/v1/whatsapp-templates/library/adopt
Required Scope: channels:admin or messages:create
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
channel_id | string | Yes | WhatsApp channel whose WABA receives the template |
library_template_name | string | Yes | The name of the library entry, e.g. delivery_update_1 |
language | string | No | Meta language code to create it in. Default en_US |
category | string | No | Defaults to the library entry's own category (UTILITY / AUTHENTICATION) |
name | string | No | Name for the created template. Defaults to library_template_name. Normalised to lowercase and underscores |
button_inputs | array | No | Your own button destinations. Omit to accept the library entry's example values — see below |
snapshot | object | No | The library entry exactly as your client displayed it, used as a content fallback if Meta rate-limits the confirmation lookup |
One-click adoption
For any entry with requires_input: false, the whole call is four fields:
curl -X POST "https://api.sendseven.com/api/v1/whatsapp-templates/library/adopt" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"channel_id": "71a1351f-4d6a-4444-9c6b-1cc8d63d7408",
"library_template_name": "delivery_update_1",
"language": "en_US"
}'
Response (201 Created)
{
"success": true,
"id": "tpl_abc123",
"template_id": "1234567890123456",
"name": "delivery_update_1",
"language": "en_US",
"status": "approved",
"category": "UTILITY",
"already_existed": false,
"error": null,
"error_code": null,
"error_subcode": null,
"error_is_retryable": false,
"fbtrace_id": "A1bCdEfGhIjKlMnOpQ"
}
id is the SendSeven template ID you send with; template_id is Meta's. An unchanged library template comes back approved and is stored that way — SendSeven deliberately does not re-sync to confirm it, because sync is the rate-limited call and your next action is to send.
On failure success is false and the response carries the parsed Graph error context (error, error_code, error_subcode, error_is_retryable, fbtrace_id); the HTTP status reflects whether a retry is worthwhile.
Button inputs
Meta's catalog ships example button destinations. Entries whose buttons open a link or dial a number are flagged requires_input: true and need one button_inputs entry per such button, in the same order as the entry's buttons of that type. QUICK_REPLY buttons take no input — Meta fills them from the library definition.
| Field | Type | Description |
|---|---|---|
type | string | URL, PHONE_NUMBER, OTP, MPM, CATALOG, FLOW, VOICE_CALL, APP |
url.base_url | string | The URL the button opens. May contain a single {{1}} variable |
url.url_suffix_example | string | Required when base_url contains a variable: the full example URL with the variable filled in |
phone_number | string | For PHONE_NUMBER buttons, in E.164 format |
otp_type | string | COPY_CODE, ONE_TAP or ZERO_TAP for authentication templates |
A URL button pointing at your own tracking page, with the order ID as the variable part:
curl -X POST "https://api.sendseven.com/api/v1/whatsapp-templates/library/adopt" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"channel_id": "71a1351f-4d6a-4444-9c6b-1cc8d63d7408",
"library_template_name": "delivery_update_1",
"language": "en_US",
"name": "delivery_update_shop",
"button_inputs": [
{
"type": "URL",
"url": {
"base_url": "https://shop.example.com/track/{{1}}",
"url_suffix_example": "https://shop.example.com/track/ORD-5678"
}
}
]
}'
A phone-number button:
{
"button_inputs": [
{ "type": "PHONE_NUMBER", "phone_number": "+4930123456789" }
]
}
Idempotency
Adopting a template the tenant already has is a no-op: the existing row is returned with already_existed: true and HTTP 200 instead of 201. Nothing is sent to Meta, so re-running an adoption after a network timeout is safe.
Send the Adopted Template
An adopted library template is an ordinary SendSeven template. Use the id from the adopt response and fill its {{1}}, {{2}} … placeholders exactly as with any positional template:
curl -X POST "https://api.sendseven.com/api/v1/whatsapp-templates/tpl_abc123/send" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"contact_id": "contact_xyz789",
"channel_id": "71a1351f-4d6a-4444-9c6b-1cc8d63d7408",
"language": "en_US",
"variable_values": ["ORD-5678", "Feb 15, 2026"]
}'
The library entry's body_params are Meta's example values, index-aligned with the placeholders, and body_param_types names what each placeholder is (order_id, date, …) when Meta provides it — useful for pre-filling or mapping your own fields.
See Send a Template Message for the full send reference, including media headers and button parameters.
End-to-End Flow
1. GET /whatsapp-templates/library?channel_id=…&language=en_US
→ pick an entry; note `requires_input`
2. POST /whatsapp-templates/library/adopt
→ { "id": "tpl_abc123", "status": "approved" }
3. POST /whatsapp-templates/tpl_abc123/send
→ template delivered, 24-hour window opens when the customer replies
Sending templates is billed by Meta to your WhatsApp Business Account, so a payment method must be on file there — instant approval does not change that. Replying to an inbound message inside the 24-hour window needs no payment method at Meta.
Next Steps
- Understanding Templates — template structure, categories, statuses
- Send a Template Message — sending with variables and buttons
- 24-Hour Messaging Window — when a template is required
- Getting Started with WhatsApp — connecting a number