API, MCP and webhooks for developers

Connect your WhatsApp inbox to your own software, your CRM and your AI assistants. Every user creates their own API key in the dashboard; the same rules (24-hour window, approved templates) apply everywhere.

REST API

Read conversations, send messages and templates, start campaigns.

MCP (AI)

Let assistants like Claude, ChatGPT and Cursor work with your inbox.

Webhooks

Receive new messages and delivery updates instantly, signed.

The API, webhooks and MCP are available on the Pro and Business plans (including the 14-day trial).

Quick start

1. Open API & MCP in the dashboard and create a key. It is shown only once, so store it somewhere safe.

Create a key in the dashboard

2. Send the key in the Authorization header with every request and make a test call:

curl https://sosyalmedya.website/api/v1/me \
  -H "Authorization: Bearer smw_live_…"

3. Send your first message with an approved template:

curl -X POST https://sosyalmedya.website/api/v1/messages \
  -H "Authorization: Bearer smw_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "905321234567",
    "template": {
      "name": "randevu_hatirlatma",
      "language": "tr",
      "params": ["Ayşe", "yarın 10:00"]
    }
  }'

Authentication and scopes

Send your personal API key as a Bearer token with every request. A key acts with the permissions of the user who created it and stops working immediately if it is revoked or the user is removed from the team.

Authorization: Bearer smw_live_…

Scopes

scope
readReads numbers, templates, conversations, messages and campaigns.
sendSends messages and templates, marks as read, starts and stops campaigns. Always includes read.

Security

  • Never use a key in a browser, a mobile app or public code; keep it on your server.
  • Giving an AI assistant a read-only key is the safest way to start.
  • If you suspect a key has leaked, revoke it in the dashboard and create a new one.

WhatsApp rules

24-hour window
You can send free-form text within 24 hours of the customer's last message (72 hours when they came from a Click-to-WhatsApp ad). The conversation's window_open field tells you.
Approved templates
To start a new conversation or write when the window is closed you must send a template approved by Meta. Create templates in the dashboard and list them with /templates.
Opt-in
Only message people who agreed to receive WhatsApp messages from you. Campaigns require opt_in_confirmed: true.
Phone format
Country code and digits only: 905321234567. Turkish mobile numbers written as 0532… or 532… are fixed automatically.
Fees
Meta's per-message fees are charged directly to your WhatsApp Business account; the API adds no message markup.

Endpoints

The base URL is below. All bodies and responses are JSON; times are ISO 8601 (UTC).

https://sosyalmedya.website/api/v1
MethodPathScopeDescription
GET/mereadBusiness, user, key scopes and connected numbers
GET/numbersreadConnected WhatsApp numbers
GET/templatesreadTemplates (?number_id=&status=APPROVED)
GET/conversationsreadConversations by last message (?search=&number_id=&page=)
GET/conversations/{id}readConversation and latest messages (?limit=1–150)
POST/conversations/{id}/readsendMark as read and send a read receipt
POST/messagessendSend text or a template
GET/messages/{id}readMessage and delivery status
GET/campaignsreadCampaigns
POST/campaignssendOpt-in bulk template sending
GET/campaigns/{id}readCampaign and counters
POST/campaigns/{id}/cancelsendStop a campaign

Examples

Start a conversation with a template

curl -X POST https://sosyalmedya.website/api/v1/messages \
  -H "Authorization: Bearer smw_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "905321234567",
    "template": {
      "name": "randevu_hatirlatma",
      "language": "tr",
      "params": ["Ayşe", "yarın 10:00"]
    }
  }'

If you have more than one number, also pass number_id when sending with to.

Reply in an open conversation (within 24 hours)

curl -X POST https://sosyalmedya.website/api/v1/messages \
  -H "Authorization: Bearer smw_live_…" \
  -H "Content-Type: application/json" \
  -d '{ "conversation_id": "CONVERSATION_ID", "text": "Merhaba, nasıl yardımcı olabilirim?" }'

Find unread conversations

curl "https://sosyalmedya.website/api/v1/conversations?page=1" \
  -H "Authorization: Bearer smw_live_…"

JavaScript (Node 18+)

const res = await fetch("https://sosyalmedya.website/api/v1/messages", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.SMW_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    to: "905321234567",
    template: { name: "randevu_hatirlatma", language: "tr", params: ["Ayşe", "yarın 10:00"] },
  }),
});
const data = await res.json();
if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
console.log(data.message.id, data.message.status);

Python

import os, requests

res = requests.post(
    "https://sosyalmedya.website/api/v1/messages",
    headers={"Authorization": f"Bearer {os.environ['SMW_API_KEY']}"},
    json={
        "to": "905321234567",
        "template": {"name": "randevu_hatirlatma", "language": "tr", "params": ["Ayşe", "yarın 10:00"]},
    },
    timeout=30,
)
data = res.json()
if not res.ok:
    raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
print(data["message"]["id"], data["message"]["status"])

Errors

Errors return an HTTP status code and the body below. Branch on code; message is meant for humans.

{
  "error": {
    "code": "window_closed",
    "message": "The 24-hour customer service window is closed …",
    "detail": "no_conversation"
  }
}
codeHTTPMeaning
unauthorized401Key missing, wrong or revoked
insufficient_scope403Read-only key; the send scope is required
plan_upgrade_required402Plan does not include the API (Pro or Business required)
subscription_inactive402Subscription is not active
validation_failed422Invalid field; detail tells which one
not_found404Not found or not owned by this business
window_closed40924-hour window closed or no conversation yet: send a template
no_wa_account409No WhatsApp number connected
template_not_available422Template missing, not approved or not in that language
undeliverable422The number may not be on WhatsApp
rate_limited429Rate limit exceeded; wait for Retry-After

Rate limits

  • 120 requests per minute per key (or connected app).
  • Of those, at most 30 sends per minute (messages, read receipts, campaigns). AI (MCP) connections are limited to 10 sends per minute.
  • Over the limit you get 429 with Retry-After: 60. For bulk sending use campaigns instead of one-by-one messages; campaigns are sent in batches that respect Meta's throughput limits.

Webhooks

The account owner can add up to 3 https URLs under API & MCP → Webhooks in the dashboard. Each event arrives at your URL as a POST with a JSON body.

Events

event
message.receivedA new message from a customer (text, media, location, reaction…).
message.statusThe status of a message you sent changed: sent, delivered, read, failed.

Headers

header
X-SMW-EventEvent type
X-SMW-Event-IdEvent id; use it to drop duplicates
X-SMW-DeliveryId of this delivery
X-SMW-Signaturet=<unix time>,v1=<signature>

Example body

{
  "id": "evt_5f0c2a1e-…",
  "type": "message.received",
  "created_at": "2026-10-19T09:41:12.000Z",
  "data": {
    "message": {
      "id": "…", "conversation_id": "…", "number_id": "…",
      "direction": "in", "type": "text", "text": "Fiyat alabilir miyim?",
      "status": "received", "source": "contact", "media": null,
      "created_at": "2026-10-19T09:41:11.000Z"
    },
    "conversation": {
      "id": "…", "contact": { "wa_id": "905321234567", "name": "Ayşe" },
      "unread_count": 1, "window_open": true,
      "window_expires_at": "2026-10-20T09:41:11.000Z"
    },
    "number": { "id": "…", "display_phone_number": "+90 532 000 00 00" }
  }
}

Verifying the signature

The signature is HMAC-SHA256("<t>.<raw body>") with the secret shown in the dashboard. Verify the raw body before parsing it and reject timestamps older than 5 minutes.

Node.js

import crypto from "node:crypto";

// rawBody: ayrıştırılmamış gövde (string) · header: X-SMW-Signature
export function verifySignature(rawBody, header, secret) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${parts.t}.${rawBody}`).digest("hex");
  return expected.length === parts.v1?.length &&
    crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1));
}

Python

import hashlib, hmac, time

def verify_signature(raw_body: bytes, header: str, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    if abs(time.time() - int(parts["t"])) > 300:
        return False
    expected = hmac.new(secret.encode(), parts["t"].encode() + b"." + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, parts.get("v1", ""))

Delivery and retries

  • An event counts as delivered when you return 2xx within 10 seconds.
  • Otherwise it is retried after 1 min, 5 min, 30 min, 2 h, 6 h, 12 h and 24 h (8 attempts in total).
  • After 25 consecutive failures the URL is paused automatically; you can re-enable it in the dashboard.
  • The same event may arrive more than once; deduplicate with X-SMW-Event-Id.

MCP: AI assistants

MCP (Model Context Protocol) is an open standard that lets AI assistants use external systems as tools. Our MCP server lets your assistant read your inbox and, with your approval, send messages.

MCP server

https://sosyalmedya.website/api/mcp

Claude and ChatGPT (one-click connect)

  1. Claude: paste the MCP URL in Settings → Connectors → "Add custom connector". ChatGPT: add a new app (connector) in developer mode with the same URL.
  2. Sign in with your sosyalmedya.website account on the page that opens, choose the permissions and approve. If you do not grant sending, the connection is read-only.
  3. You can disconnect anytime under API & MCP → Connected AI apps in the dashboard.

With an API key (Claude Code, Cursor, VS Code, Windsurf)

These tools support OAuth too; if you prefer not to share a key, add just the URL and a sign-in page opens on first use.

Claude Code

# OAuth (tarayıcıda giriş) / OAuth (sign in in the browser)
claude mcp add --transport http sosyalmedya https://sosyalmedya.website/api/mcp

# API anahtarıyla / With an API key
claude mcp add --transport http sosyalmedya https://sosyalmedya.website/api/mcp \
  --header "Authorization: Bearer smw_live_…"

Cursor — .cursor/mcp.json

{
  "mcpServers": {
    "sosyalmedya": {
      "url": "https://sosyalmedya.website/api/mcp",
      "headers": {
        "Authorization": "Bearer smw_live_…"
      }
    }
  }
}

VS Code — .vscode/mcp.json

{
  "servers": {
    "sosyalmedya": {
      "type": "http",
      "url": "https://sosyalmedya.website/api/mcp",
      "headers": {
        "Authorization": "Bearer smw_live_…"
      }
    }
  }
}

Windsurf — ~/.codeium/windsurf/mcp_config.json

{
  "mcpServers": {
    "sosyalmedya": {
      "serverUrl": "https://sosyalmedya.website/api/mcp",
      "headers": {
        "Authorization": "Bearer smw_live_…"
      }
    }
  }
}

Tools

ToolScopeWhat it does
get_accountreadBusiness, plan, connection scopes and numbers
list_whatsapp_numbersreadConnected numbers
list_templatesreadApproved templates and their variable counts
list_conversationsreadConversations, unread counts, window state
get_conversationreadLatest messages of a conversation
get_message_statusreadDelivered / read / failed
send_text_messagesendFree-form text in an open window
send_template_messagesendApproved template (new conversation or closed window)
mark_conversation_readsendMark as read

Safety principles

  • Sending tools are marked as having external effects, so assistants ask for your confirmation before sending.
  • Bulk campaigns are intentionally not available over MCP: an AI messaging many people by mistake could lower your number's quality rating. Start campaigns from the dashboard or the REST API.
  • Customer messages are marked as untrusted content and the assistant is told not to follow instructions inside them. Grant sending only to assistants you trust.
  • The assistant only sees what the connected user can see.

OpenAPI and versioning

A machine-readable description of every endpoint is available as OpenAPI 3.1. Import it into Postman, n8n, Make or ChatGPT Actions.

https://sosyalmedya.website/api/v1/openapi.json

Version 1 is stable: new fields and endpoints may be added, existing ones do not change. A breaking change would ship as /api/v2 and be announced in advance.

Questions: [email protected]