Introduction

The TrustForce Hosting API lets your app send and receive WhatsApp messages, manage automated keyword replies, and pull message history — all through one REST API backed by your linked WhatsApp number(s).

Base URL for every endpoint below:

https://wa.trustforce.co.za/api/v1/

Authentication

Every request needs your API key (from Dashboard → API keys) in the Authorization header:

Authorization: Bearer tfh_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Most endpoints also accept an optional session parameter — the session key shown on your WhatsApp number's card in the dashboard. If you leave it out, the key's default number is used.

Errors

Errors come back as JSON with an error field and a standard HTTP status code:

CodeMeaning
401Missing, invalid, or revoked API key
403Key doesn't have the required permission, or account suspended
404Endpoint or resource not found
409WhatsApp number not connected yet
422Missing or invalid parameter
429Plan limit reached (messages, webhooks, or rules)
502The open-wa server returned an error

Send a message

POST /api/v1/send

Requires the send scope. Sends a text message, or an image/document by URL.

ParamDescription
toDestination number, digits with country code (e.g. 27825550142)
messageText body (required unless sending media)
media_urlPublic URL of an image/document to send instead of text
media_typeimage | document | video (default image)
captionOptional caption for media
sessionOptional session key, if not using the key's default
# Example curl -X POST https://wa.trustforce.co.za/api/v1/send \ -H "Authorization: Bearer tfh_live_xxxx" \ -H "Content-Type: application/json" \ -d '{"to":"27825550142","message":"Hello from my app!"}'
// 200 response { "success": true, "to": "27825550142@c.us", "data": { "...open-wa server response..." } }

Session status

GET /api/v1/status?session=tfh_u12_a9f3

Requires the read scope. Returns connection state for one number.

{ "session": "tfh_u12_a9f3", "label": "Support line", "status": "connected", "phone_number": "27825550142", "connected_at": "2026-05-02 10:14:00" }

List your numbers

GET /api/v1/sessions

Requires the read scope. Returns every WhatsApp number on your account.

Webhooks

GET /api/v1/webhooks
POST /api/v1/webhooks

Requires the webhook scope. List or create webhooks. Creating one returns a forward_secret used to sign forwarded events (see below).

Param (POST)Description
sessionSession key this webhook listens on
nameA label for the webhook
forward_urlOptional — your server's URL to receive raw events

Keyword rules

GET /api/v1/rules?webhook_id=4
POST /api/v1/rules
DELETE /api/v1/rules

Requires the webhook scope. Manage the keyword → auto-reply rules attached to a webhook.

ParamDescription
webhook_idRequired on every call
keywordThe text or regex pattern to match (POST)
match_typecontains | exact | starts_with | regex
case_sensitivetrue/false, default false
reply_typetext | image | document | no_reply
reply_textReply body or caption
reply_media_urlURL for image/document replies
priorityLower number is checked first
idRule id (DELETE only)
# Auto-reply to anything containing "price" curl -X POST https://wa.trustforce.co.za/api/v1/rules \ -H "Authorization: Bearer tfh_live_xxxx" \ -H "Content-Type: application/json" \ -d '{ "webhook_id": 4, "keyword": "price", "match_type": "contains", "reply_type": "text", "reply_text": "Our plans start at $29/mo — want the full list?" }'

Message logs

GET /api/v1/logs?limit=50

Requires the read scope. Returns your most recent inbound and outbound messages, newest first.

Receiving messages: forwarded events

If you set a forward_url on a webhook, every inbound message on that number is POSTed to your server as it arrives — whether or not it matched a keyword rule:

{ "event": "message.received", "webhook_id": 4, "message": { "from": "27825550142@c.us", "body": "do you ship to durban?", "...raw open-wa event fields..." }, "matched_rule": 12, "timestamp": "2026-06-24T10:15:00+00:00" }

matched_rule is the id of the keyword rule that fired, or null if nothing matched.

Verifying signatures

Every forwarded request includes an X-TFH-Signature header: an HMAC-SHA256 of the raw request body, signed with the webhook's forward_secret. Verify it before trusting the payload:

// PHP $payload = file_get_contents('php://input'); $expected = hash_hmac('sha256', $payload, $webhookSecret); if (!hash_equals($expected, $_SERVER['HTTP_X_TFH_SIGNATURE'] ?? '')) { http_response_code(401); exit('Invalid signature'); }

Need something the API doesn't cover yet?