Outbound API
Send WhatsApp, Facebook, and Instagram messages from your own server through SocialHook. One signed endpoint covers all three platforms β your code doesn't change when you add a new platform.
When to use this
{ "reply": "..." } to auto-send a message back without calling this endpoint at all. See Auto-reply below.1. Get an API key
Open API key in your dashboard and click Generate. You'll see the full key once β copy it now and store it somewhere safe (e.g. your secrets manager). If you lose it, generate a new one; the old one stops working immediately.
Keys start with sk_live_ followed by 64 hex characters. Treat it like a password: never commit it to git, never expose it in browser code.
2. Endpoint
POST https://api.socialhook.io/api/v1/outbound/<your_user_id>/send Content-Type: application/json
Your user_id is shown in the URL on the API key page. The path is user-scoped on purpose so a leaked key can only impact one account.
3. Authentication
Choose the method that fits your setup. Both work with the same endpoint.
Method A β Simple key (n8n, Make, Zapier, no-code tools)
Add a single header. No signing required.
X-Api-Key: <your_api_key>
# Method: POST
# URL: https://api.socialhook.io/api/v1/outbound/<your_user_id>/send
# Header: X-Api-Key β sk_live_β¦
# Body (JSON):
{
"platform": "whatsapp",
"to": "447911123456",
"message_text": "Hello from n8n!"
}Method B β Signed request (HMAC-SHA256, custom servers)
Build the signature by HMAC-SHA256-hashing <timestamp>.<raw_body> with your API key, then send the lowercase hex digest in the X-Socialhook-Signature header prefixed with sha256=. Requests with timestamps more than 5 minutes from server time are rejected.
X-Socialhook-Timestamp: <unix_seconds> X-Socialhook-Signature: sha256=<hmac_hex>
const crypto = require('crypto');
const API_KEY = process.env.SOCIALHOOK_API_KEY; // sk_live_β¦
const USER_ID = process.env.SOCIALHOOK_USER_ID; // shown on the API key page
const body = JSON.stringify({
platform: 'whatsapp',
to: '447911123456',
message_text: 'Hello from your SocialHook integration!',
});
const ts = Math.floor(Date.now() / 1000).toString();
const sig = crypto
.createHmac('sha256', API_KEY)
.update(`${ts}.${body}`)
.digest('hex');
const res = await fetch(
`https://api.socialhook.io/api/v1/outbound/${USER_ID}/send`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Socialhook-Timestamp': ts,
'X-Socialhook-Signature': `sha256=${sig}`,
},
body,
}
);
if (!res.ok) throw new Error(await res.text());# Drop your real API_KEY and USER_ID in here
TS=$(date +%s)
BODY='{"platform":"whatsapp","to":"447911123456","message_text":"Hello!"}'
SIG=$(printf "%s.%s" "$TS" "$BODY" | openssl dgst -sha256 -hmac "$API_KEY" | awk '{print $2}')
curl -X POST https://api.socialhook.io/api/v1/outbound/$USER_ID/send \
-H "Content-Type: application/json" \
-H "X-Socialhook-Timestamp: $TS" \
-H "X-Socialhook-Signature: sha256=$SIG" \
-d "$BODY"4. Request body per platform
{
"platform": "whatsapp",
"to": "447911123456",
"message_text": "Hello from your integration!"
}"to" is the recipient phone number in E.164 format (no leading +).
{
"platform": "facebook",
"to": "<recipient_psid>",
"page_id": "<your_facebook_page_id>",
"message_text": "Hi from SocialHook"
}"to" is the page-scoped user id (PSID). "page_id" is required so we know which page to send from.
{
"platform": "instagram",
"to": "<recipient_psid>",
"page_id": "<your_facebook_page_id>",
"message_text": "Hey from SocialHook"
}"to" is the IG-scoped user id. "page_id" is the linked Facebook Page id (Instagram piggybacks the FB OAuth).
5. Response codes
| Code | Meaning | What to do |
|---|---|---|
200 | Sent | Message accepted by the platform; appears in the chat thread. |
400 | Bad request | Missing or invalid field. Check platform/to/message_text/page_id. |
401 | Unauthorized | X-Api-Key missing/invalid, or X-Socialhook-Signature did not match. Recompute it with the exact raw body. |
403 | Window expired | 24-hour messaging window closed (FB / IG / WA). Wait for an inbound message before replying. |
408 | Timestamp too old | X-Socialhook-Timestamp is more than 5 minutes from server time. Resend with a fresh timestamp. |
429 | Rate limited | Too many requests. Back off and retry. |
Auto-reply (skip the endpoint)
If your only outbound need is responding to incoming messages, you don't need to call this endpoint at all. When SocialHook delivers a webhook to you, your server can respond with one of:
// Single reply
{ "reply": "Thanks β got your message!" }
// Or multiple in order
{ "replies": ["Thanks!", "We'll get back to you within an hour."] }SocialHook sends each reply on the right platform automatically and records it in the chat thread. Reply failures don't block delivery acknowledgement β your webhook is still marked DELIVERED.