curl --request POST \
--url https://app.famulor.io/api/v1/whatsapp/templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "create",
"connector_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"template_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"body_text": "<string>",
"library_template_name": "<string>",
"library_button_values": {},
"language": "<string>",
"parameter_bindings": {},
"opt_out_buttons": [
"<string>"
],
"components": [
{}
],
"to_number": "<string>",
"context": {}
}
'import requests
url = "https://app.famulor.io/api/v1/whatsapp/templates"
payload = {
"action": "create",
"connector_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"template_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"body_text": "<string>",
"library_template_name": "<string>",
"library_button_values": {},
"language": "<string>",
"parameter_bindings": {},
"opt_out_buttons": ["<string>"],
"components": [{}],
"to_number": "<string>",
"context": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
action: 'create',
connector_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
template_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
name: '<string>',
body_text: '<string>',
library_template_name: '<string>',
library_button_values: {},
language: '<string>',
parameter_bindings: {},
opt_out_buttons: ['<string>'],
components: [{}],
to_number: '<string>',
context: {}
})
};
fetch('https://app.famulor.io/api/v1/whatsapp/templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.famulor.io/api/v1/whatsapp/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'action' => 'create',
'connector_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'template_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'name' => '<string>',
'body_text' => '<string>',
'library_template_name' => '<string>',
'library_button_values' => [
],
'language' => '<string>',
'parameter_bindings' => [
],
'opt_out_buttons' => [
'<string>'
],
'components' => [
[
]
],
'to_number' => '<string>',
'context' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.famulor.io/api/v1/whatsapp/templates"
payload := strings.NewReader("{\n \"action\": \"create\",\n \"connector_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"template_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"body_text\": \"<string>\",\n \"library_template_name\": \"<string>\",\n \"library_button_values\": {},\n \"language\": \"<string>\",\n \"parameter_bindings\": {},\n \"opt_out_buttons\": [\n \"<string>\"\n ],\n \"components\": [\n {}\n ],\n \"to_number\": \"<string>\",\n \"context\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.famulor.io/api/v1/whatsapp/templates")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"action\": \"create\",\n \"connector_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"template_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"body_text\": \"<string>\",\n \"library_template_name\": \"<string>\",\n \"library_button_values\": {},\n \"language\": \"<string>\",\n \"parameter_bindings\": {},\n \"opt_out_buttons\": [\n \"<string>\"\n ],\n \"components\": [\n {}\n ],\n \"to_number\": \"<string>\",\n \"context\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.famulor.io/api/v1/whatsapp/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"action\": \"create\",\n \"connector_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"template_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"body_text\": \"<string>\",\n \"library_template_name\": \"<string>\",\n \"library_button_values\": {},\n \"language\": \"<string>\",\n \"parameter_bindings\": {},\n \"opt_out_buttons\": [\n \"<string>\"\n ],\n \"components\": [\n {}\n ],\n \"to_number\": \"<string>\",\n \"context\": {}\n}"
response = http.request(request)
puts response.read_body{
"error": {
"code": "rate_limited",
"message": "Too many requests. Retry after the indicated delay."
}
}{
"error": {
"code": "internal_error",
"message": "Request protection is temporarily unavailable."
}
}Create / update / submit / sync / send / delete WhatsApp templates
Body.action: create | update | submit | sync | send | set_opt_out_buttons | delete. Sync follows all provider pages and imports templates that do not yet exist locally. Draft updates remain local. On editable provider templates, only component or category changes are sent to Meta; parameter mappings and opt-out configuration remain local. Submit returns the provider-controlled review status. Send supports text headers/body plus static quick-reply, URL, phone and call-permission components; templates requiring runtime media, location, dynamic-URL or copy-code values are rejected locally. Required scope: assistants:write. Requires WhatsApp text in the workspace plan.
curl --request POST \
--url https://app.famulor.io/api/v1/whatsapp/templates \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"action": "create",
"connector_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"template_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"body_text": "<string>",
"library_template_name": "<string>",
"library_button_values": {},
"language": "<string>",
"parameter_bindings": {},
"opt_out_buttons": [
"<string>"
],
"components": [
{}
],
"to_number": "<string>",
"context": {}
}
'import requests
url = "https://app.famulor.io/api/v1/whatsapp/templates"
payload = {
"action": "create",
"connector_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"template_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
"name": "<string>",
"body_text": "<string>",
"library_template_name": "<string>",
"library_button_values": {},
"language": "<string>",
"parameter_bindings": {},
"opt_out_buttons": ["<string>"],
"components": [{}],
"to_number": "<string>",
"context": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
action: 'create',
connector_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
template_id: '3c90c3cc-0d44-4b50-8888-8dd25736052a',
name: '<string>',
body_text: '<string>',
library_template_name: '<string>',
library_button_values: {},
language: '<string>',
parameter_bindings: {},
opt_out_buttons: ['<string>'],
components: [{}],
to_number: '<string>',
context: {}
})
};
fetch('https://app.famulor.io/api/v1/whatsapp/templates', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://app.famulor.io/api/v1/whatsapp/templates",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'action' => 'create',
'connector_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'template_id' => '3c90c3cc-0d44-4b50-8888-8dd25736052a',
'name' => '<string>',
'body_text' => '<string>',
'library_template_name' => '<string>',
'library_button_values' => [
],
'language' => '<string>',
'parameter_bindings' => [
],
'opt_out_buttons' => [
'<string>'
],
'components' => [
[
]
],
'to_number' => '<string>',
'context' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://app.famulor.io/api/v1/whatsapp/templates"
payload := strings.NewReader("{\n \"action\": \"create\",\n \"connector_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"template_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"body_text\": \"<string>\",\n \"library_template_name\": \"<string>\",\n \"library_button_values\": {},\n \"language\": \"<string>\",\n \"parameter_bindings\": {},\n \"opt_out_buttons\": [\n \"<string>\"\n ],\n \"components\": [\n {}\n ],\n \"to_number\": \"<string>\",\n \"context\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://app.famulor.io/api/v1/whatsapp/templates")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"action\": \"create\",\n \"connector_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"template_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"body_text\": \"<string>\",\n \"library_template_name\": \"<string>\",\n \"library_button_values\": {},\n \"language\": \"<string>\",\n \"parameter_bindings\": {},\n \"opt_out_buttons\": [\n \"<string>\"\n ],\n \"components\": [\n {}\n ],\n \"to_number\": \"<string>\",\n \"context\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.famulor.io/api/v1/whatsapp/templates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"action\": \"create\",\n \"connector_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"template_id\": \"3c90c3cc-0d44-4b50-8888-8dd25736052a\",\n \"name\": \"<string>\",\n \"body_text\": \"<string>\",\n \"library_template_name\": \"<string>\",\n \"library_button_values\": {},\n \"language\": \"<string>\",\n \"parameter_bindings\": {},\n \"opt_out_buttons\": [\n \"<string>\"\n ],\n \"components\": [\n {}\n ],\n \"to_number\": \"<string>\",\n \"context\": {}\n}"
response = http.request(request)
puts response.read_body{
"error": {
"code": "rate_limited",
"message": "Too many requests. Retry after the indicated delay."
}
}{
"error": {
"code": "internal_error",
"message": "Request protection is temporarily unavailable."
}
}Authorizations
API key (fam_..., created under Settings → API Keys) or an OAuth 2.0 access token (fam_at_...). REST operations also require API Access for the credential's workspace. Keys can be restricted to scopes such as assistants:read, calls:write, campaigns:write, automations:read, dashboards:read, dashboards:write, leads:write, segments:write, loop:read, loop:write, phone_numbers:write, sip_trunks:write, knowledge:write, voices:read, billing:read, billing:write, settings:write, platform:read, platform:write; a *:write scope implies the matching *:read. Automation and dashboard endpoints also accept the legacy calls:* scope. Keys without scope restrictions have full access within the workspace's available capabilities.
Body
create, update, submit, sync, send, set_opt_out_buttons, delete Template body. Variables must use positive contiguous numbering: {{1}}, {{2}}, {{3}}.
Official library preset name. When supplied with action=create, the preset is created directly for the sender.
Button index to HTTPS URL or E.164 phone number. Required for official library templates with URL or phone-number buttons.
Show child attributes
Show child attributes
UTILITY, MARKETING, AUTHENTICATION Maps component positions (1, 2, header.1) to system, lead, assistant, or custom variable keys.
Show child attributes
Show child attributes
Canonical QUICK_REPLY labels whose tap suppresses the contact. With action=set_opt_out_buttons this is always a local-only update.
Ordered template components. The core composer supports HEADER (TEXT, IMAGE, VIDEO, DOCUMENT, LOCATION), BODY, FOOTER, and BUTTONS (QUICK_REPLY, URL, PHONE_NUMBER, COPY_CODE). Media headers require example.header_handle from the provider review upload flow. Updates replace the complete component array. Call-permission templates use a BODY plus a CALL_PERMISSION_REQUEST component.
Show child attributes
Show child attributes
Response
Action result.