Sikio API · v1
Delivery, errors and safe retries
Request status
| Status | Meaning | Next action |
|---|---|---|
processing | A caller owns the request. | Poll using the original credential. A stuck request needs reconciliation. |
accepted | WhatsApp returned a message ID. | Check receipts; acceptance alone is not delivery. |
failed | Preparation failed before sending or the provider explicitly rejected it. | Inspect the error. Correct the cause before creating a replacement request. |
uncertain | The provider outcome could not be established. | Reconcile before attempting a replacement send. Do not blindly resend. |
Send returns HTTP 202 for accepted, processing and uncertain outcomes, and HTTP 422 for failed requests. Inspect both the HTTP status and the body’s status.
Delivery receipts
Poll GET /v1/integrations/whatsapp/messages/{request_id} with the original credential and whatsapp:read. delivery_status is unknown, delivered or read when available. Check delivered_at and read_at. An absent receipt does not prove failure.
The current receipt model does not expose a reliable post-acceptance provider-failure status. Outbound webhook subscriptions are not part of this API version. An accepted request can carry a bookkeeping reconciliation warning in error; do not resend it automatically.
Replace REQUEST_ID with the send response’s id.
curl --fail-with-body \
--user 'YOUR_API_KEY:YOUR_API_SECRET' \
--write-out '\nHTTP %{http_code}\n' \
'https://stage.api.ictlife.com/v1/integrations/whatsapp/messages/REQUEST_ID'const credentials = Buffer.from('YOUR_API_KEY:YOUR_API_SECRET').toString('base64');
const response = await fetch("https://stage.api.ictlife.com/v1/integrations/whatsapp/messages/REQUEST_ID", {
method: 'GET',
headers: {
Authorization: 'Basic ' + credentials,
},
});
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}
request = urllib.request.Request("https://stage.api.ictlife.com/v1/integrations/whatsapp/messages/REQUEST_ID", method='GET', headers=headers)
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()}')Idempotency
The required Idempotency-Key accepts 1–128 letters, digits, dots, underscores, colons or hyphens. Its namespace is the workspace and API credential, across channels. Reusing the same key with an identical payload returns the same request without another provider send. Changing the payload or channel returns HTTP 409.
Keep the original credential, key and body together. Rotation starts a new namespace. A failed request retains its key; after understanding the failure, a corrected intended send uses a new key. Transport timeouts, provider HTTP 408/5xx and malformed responses may be uncertain. Do not treat them as permission to create a new send.
HTTP errors
| HTTP | What to check |
|---|---|
| 400 | Payload, identifiers, template fields or channel availability. Inspect the returned error. |
| 401 / 403 | Credential validity and required scopes. Check the workspace and environment. |
| 404 | Resource ownership, original sending credential and authentication. The platform can mask an unauthenticated request as 404. |
| 409 | Idempotency key reused for a different request. |
| 422 | A failed send request: inspect status and error. |
| 429 | Honor Retry-After and retry with the same request identity. |
| 5xx / timeout | Reconcile sends before retrying or replacing them. |
Platform errors normally include error_code and error_message; inspect these with the HTTP status. Rate-limit and send-request responses can instead include error as shown in the endpoint reference.
Limits
- Send JSON body: 32 KiB. Template ID: up to 128 bytes; external reference: up to 256 bytes.
- Template variables: up to 100 string pairs; keys 1–128 bytes, values up to 4,096 bytes.
- Context: up to 25 string pairs; keys 1–64 bytes, values up to 1,024 bytes.
- Unknown send fields and trailing JSON are rejected. Never send credentials inside the body.
- New sends: 60 per minute per credential across replicas; identical replays do not consume another slot. Current Retry-After is 60 seconds.
Media upload limits are separate from send limits.
Next guideAPI reference →