Sikio API · v1
Template types and variables
Start with the template returned by channel discovery. Send its ID and only the variables supported by its components. Do not submit raw components, a separate language override or a template definition.
Fixed-text templates
If the approved template has no variable fields, omit template_variables. Static text, fixed buttons and the footer come from the saved template.
{
"recipient": "+254700000001",
"template_id": "YOUR_APPROVED_FIXED_TEXT_TEMPLATE_ID"
}Text variables
| Template field | Example key | Value |
|---|---|---|
Body {{1}} | body:1 | Amina |
Named body {{customer_name}} | body:customer_name | Amina |
Text header {{1}} | header:1 | Order ready |
Named text header {{order_status}} | header:order_status | Ready |
Follow the placeholder names and order in the approved definition. Do not send both named and positional alternatives unless the template actually contains both fields. Values are strings.
Buttons
Button numbering starts at one and includes fixed buttons. If the second button has a URL variable {{1}}, use button_2:1. Supply the variable portion expected by the approved URL, rather than replacing the whole button.
| Button | Send-time value |
|---|---|
| Fixed URL or phone-number button | No variable needed; preserve the approved button. |
| Dynamic URL | button_1:1 for its {{1}} placeholder, or the actual discovered placeholder name. |
| Quick reply | Optional supported payload: button_1:payload. |
| Flow | Supported token override: button_1:flow_token. The approved flow remains unchanged. |
{
"template_variables": {
"body:1": "Amina",
"button_2:1": "ORDER-1042"
}
}Media headers are optional capabilities
For image, video or document templates, omit header:media_id to use the template’s saved default. To change the asset for one message, supply a sendable WhatsApp media ID on that channel. Fixed-text and text-variable templates do not need this field. See media defaults and overrides.
Carousel cards
Prefix a card’s variable keys with card_1:, card_2:, and so on. A returned zero-based card_index: 0 maps to card_1:. Each card’s omitted media uses its own available default or original supported asset.
{
"template_variables": {
"body:1": "Amina",
"card_1:body:1": "Blue",
"card_1:button_1:1": "ITEM-101",
"card_2:header:media_id": "WHATSAPP_MEDIA_ID"
}
}Send your chosen template
Replace the recipient and template ID in the request below. For the button and carousel examples above, add their template_variables to this payload.
Replace CHANNEL_ID with your channel’s id. Use your recipient and approved template ID. Add variables or media only when that template needs them. Replace UNIQUE_MESSAGE_KEY for each new message; keep it unchanged when retrying that message.
curl --fail-with-body \
--user 'YOUR_API_KEY:YOUR_API_SECRET' \
--write-out '\nHTTP %{http_code}\n' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: UNIQUE_MESSAGE_KEY' \
--data-binary @- \
'https://stage.api.ictlife.com/v1/integrations/whatsapp/channels/CHANNEL_ID/messages' <<'JSON'
{
"recipient": "+254700000001",
"template_id": "YOUR_APPROVED_TEMPLATE_ID"
}
JSONconst credentials = Buffer.from('YOUR_API_KEY:YOUR_API_SECRET').toString('base64');
const response = await fetch("https://stage.api.ictlife.com/v1/integrations/whatsapp/channels/CHANNEL_ID/messages", {
method: 'POST',
headers: {
Authorization: 'Basic ' + credentials,
'Content-Type': 'application/json',
'Idempotency-Key': 'UNIQUE_MESSAGE_KEY',
},
body: JSON.stringify({
"recipient": "+254700000001",
"template_id": "YOUR_APPROVED_TEMPLATE_ID"
}),
});
const text = await response.text();
if (!response.ok) throw new Error(`HTTP ${response.status}: ${text}`);
console.log(response.status, text ? JSON.parse(text) : null);import base64, json
import urllib.request, urllib.error
credentials = base64.b64encode(b'YOUR_API_KEY:YOUR_API_SECRET').decode()
headers = {'Authorization': 'Basic ' + credentials}
body = json.dumps({
"recipient": "+254700000001",
"template_id": "YOUR_APPROVED_TEMPLATE_ID"
}).encode()
headers['Content-Type'] = 'application/json'
headers['Idempotency-Key'] = 'UNIQUE_MESSAGE_KEY'
request = urllib.request.Request("https://stage.api.ictlife.com/v1/integrations/whatsapp/channels/CHANNEL_ID/messages", method='POST', headers=headers, data=body)
try:
with urllib.request.urlopen(request, timeout=30) as response:
text = response.read().decode()
print(response.status, json.loads(text) if text else None)
except urllib.error.HTTPError as error:
raise SystemExit(f'HTTP {error.code}: {error.read().decode()}')Validation and support boundaries
These examples illustrate key shapes, not a template definition you can send to every channel. Required fields must match your actual approved template. Sikio rejects surplus variables, missing values and unsupported components before a provider send.
Supported integration component families are body, text/image/video/document headers, fixed footer, URL/phone/quick-reply/flow buttons and supported carousels. Dynamic footers, unsupported header formats and other button/component families are not accepted by this API version.
Next guideMedia assets: defaults and overrides →