Limited-time offers are
MARKETING only, allow no footer, and have at most two buttons (COPY_CODE and URL). See Create Template → Limited-time offer rules.Components
| Component | When | Parameter |
|---|---|---|
header | Template has an image or video header | image or video |
body | Body has variables | text per variable |
limited_time_offer | Template has hasExpiration: true | { "type": "limited_time_offer", "limited_time_offer": { "expiration_time_ms": ... } } |
button / copy_code | Template has a Copy Code button | coupon_code |
button / url | Template has a dynamic URL button | text |
expiration_time_ms is a Unix timestamp in milliseconds. WhatsApp counts down to it and shows the offer as expired afterwards.
Send a limited-time offer
curl -X POST https://api.gateway.connexease.com/v1/wa/message \
-H "Authorization: Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"messaging_product": "whatsapp",
"to": "905321234567",
"type": "template",
"template": {
"name": "flash_sale",
"language": { "code": "en" },
"components": [
{
"type": "header",
"parameters": [{ "type": "image", "image": { "link": "https://example.com/flash-banner.jpg" } }]
},
{
"type": "body",
"parameters": [{ "type": "text", "text": "John" }]
},
{
"type": "limited_time_offer",
"parameters": [
{ "type": "limited_time_offer", "limited_time_offer": { "expiration_time_ms": 1792753200000 } }
]
},
{
"type": "button",
"sub_type": "copy_code",
"index": "0",
"parameters": [{ "type": "coupon_code", "coupon_code": "FLASH40" }]
}
]
}
}'
import time
import requests
expires_at_ms = int((time.time() + 48 * 3600) * 1000) # 48 hours from now
requests.post(
"https://api.gateway.connexease.com/v1/wa/message",
headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "Content-Type": "application/json"},
json={
"messaging_product": "whatsapp",
"to": "905321234567",
"type": "template",
"template": {
"name": "flash_sale",
"language": {"code": "en"},
"components": [
{"type": "header", "parameters": [
{"type": "image", "image": {"link": "https://example.com/flash-banner.jpg"}}
]},
{"type": "body", "parameters": [{"type": "text", "text": "John"}]},
{"type": "limited_time_offer", "parameters": [
{"type": "limited_time_offer", "limited_time_offer": {"expiration_time_ms": expires_at_ms}}
]},
{"type": "button", "sub_type": "copy_code", "index": "0",
"parameters": [{"type": "coupon_code", "coupon_code": "FLASH40"}]}
]
}
}
)
const expiresAtMs = Date.now() + 48 * 60 * 60 * 1000; // 48 hours from now
await fetch('https://api.gateway.connexease.com/v1/wa/message', {
method: 'POST',
headers: { 'Authorization': 'Bearer sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx', 'Content-Type': 'application/json' },
body: JSON.stringify({
messaging_product: 'whatsapp',
to: '905321234567',
type: 'template',
template: {
name: 'flash_sale',
language: { code: 'en' },
components: [
{ type: 'header', parameters: [{ type: 'image', image: { link: 'https://example.com/flash-banner.jpg' } }] },
{ type: 'body', parameters: [{ type: 'text', text: 'John' }] },
{ type: 'limited_time_offer', parameters: [
{ type: 'limited_time_offer', limited_time_offer: { expiration_time_ms: expiresAtMs } }
] },
{ type: 'button', sub_type: 'copy_code', index: '0', parameters: [{ type: 'coupon_code', coupon_code: 'FLASH40' }] }
]
}
}),
});
expiration_time_ms is in milliseconds. Sending seconds puts the deadline in 1970, and the offer appears expired on arrival.