Documentation
Quickstart
FusionWA provides WhatsApp Business Cloud API infrastructure for SaaS companies and software houses. Your customers connect their own WhatsApp Business accounts through Meta Embedded Signup — you get the API and webhooks.
SDK Widget
Customers connect on their own. 3 lines of HTML.
REST API
Send messages and manage connections from your backend.
Webhooks
Receive messages and status updates in real time.
Coexistence
Eligible customers keep WhatsApp Business on their phone.
Step 1 — Create an account and application
Register at fusionwa.com/register. Then go to Applications and create your first App. Copy the API Key and API Secret.
Step 2 — Embed the connection widget
Add the SDK to your frontend. The widget renders a "Connect WhatsApp" button for each of your customers.
<script src="https://fusionwa.com/sdk/v1.js"></script>
<div id="fusionwa-widget"></div>
<script>
FusionWA.init({
apiKey: "fwa_live_...", // from your FusionWA dashboard (safe to expose client-side)
customerId: currentUser.id, // your internal customer ID
containerId: "fusionwa-widget",
});
</script>The SDK renders a secure iframe hosted by fusionwa.com, so you do not need to register your own domain with Meta. If your site uses a Content Security Policy, allow https://fusionwa.com in both script-src andframe-src.
Step 3 — Customer connects through Meta Embedded Signup
Your customer clicks "Connect WhatsApp". Meta Embedded Signup opens in a popup. They authorize their WhatsApp Business account. FusionWA receives and stores the connection securely.
For eligible WhatsApp Business App numbers, Meta may offer the Coexistence flow — see the Coexistence section for details.
Step 4 — Configure your webhook
In the dashboard under Applications, set a webhook URL. FusionWA will forward every incoming message and status update to your endpoint in real time.
Step 5 — Send your first message
curl -X POST https://fusionwa.com/api/v1/messages/send \
-H "X-FusionWA-API-Key: fwa_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "+39 02 1234567",
"templateName": "hello_world",
"languageCode": "it"
}'
# Response: { "messageId": "wamid.abc123..." }SDK Widget
The fastest way to integrate FusionWA. Paste the snippet into your software: the widget manages the full Meta Embedded Signup flow and WhatsApp Business connection on behalf of your customer.
Initialization
FusionWA.init({
apiKey: "fwa_live_abc123", // public — from your FusionWA dashboard
customerId: currentUser.id, // unique string per customer in YOUR system
containerId: "fusionwa-widget", // id of the div to render into
});Widget states
NOT_SUBSCRIBEDCustomer not yet activated. Shows "Activate" button.SUBSCRIBED_UNCONNECTEDActivated but not yet connected. Shows "Connect WhatsApp" button.CONNECTEDWhatsApp Business connected. Shows number and status.customerId
Use your internal customer identifier — any unique string per App. AppUsers are created automatically on first SDK init. The same customerId is used in API calls to reference that customer's connection.
apiKey is intentionally public — it only looks up connection status. Keep the API Secret server-side.WhatsApp Business App Coexistence
Coexistence is a Meta feature that allows a WhatsApp Business App number to be connected to the WhatsApp Business Cloud API simultaneously. When active, the customer continues receiving messages on their phone while the Cloud API (FusionWA) can also send and receive on the same number.
Who it applies to
Coexistence applies to eligible customers who already have an active WhatsApp Business App installation on a mobile device. Not every account is eligible — Meta determines eligibility during the Embedded Signup flow.
The Coexistence flow
When a customer connects via FusionWA and Meta offers Coexistence:
- Customer clicks "Connect WhatsApp" in your software.
- Meta Embedded Signup popup opens.
- Customer selects their existing WhatsApp Business account.
- Meta may prompt the customer to scan a QR code on their phone (this is Meta's process, not FusionWA's).
- Customer scans the QR in their WhatsApp Business App when requested.
- Connection completes — the number is now live on both the phone app and the Cloud API.
After connecting with Coexistence
The customer continues using WhatsApp Business on their phone normally — sending and receiving from the app as before. The Cloud API (your software via FusionWA) can also send messages and receives all incoming messages via webhook simultaneously.
Coexistence heartbeat
FusionWA automatically manages the Coexistence heartbeat with Meta. No additional configuration is required on your end.
// No extra configuration needed.
// FusionWA automatically manages the Coexistence
// heartbeat with Meta.
//
// The number stays active on both the mobile app
// and the Cloud API simultaneously.REST API
Full machine-readable spec: /openapi.yaml (OpenAPI 3.1 — import into Postman or Insomnia).
Widget endpoints (called from the browser) require only x-fusionwa-api-key. Server-to-server endpoints also require x-fusionwa-api-secret.
Send a template message
POST /api/v1/messages/send
x-fusionwa-api-key: fwa_live_...
x-fusionwa-api-secret: <your-secret>
{
"externalCustomerId": "user_123",
"toPhoneNumber": "+393331234567",
"template": {
"name": "booking_confirmation",
"language": "it",
"bodyParams": ["Mario Rossi", "15 set 10:00"]
}
}
# Response
{ "status": "success", "messageId": "wamid.abc123..." }Send a free-form text message
POST /api/v1/messages/send
x-fusionwa-api-key: fwa_live_...
x-fusionwa-api-secret: <your-secret>
{
"externalCustomerId": "user_123",
"toPhoneNumber": "+393331234567",
"message": "La tua prenotazione è confermata."
}
# Only valid within a 24-hour customer-initiated windowCheck connection status
GET /api/v1/widget/status?customerId=user_123
x-fusionwa-api-key: fwa_live_...
# Response — one of:
{ "status": "NOT_SUBSCRIBED" }
{ "status": "SUBSCRIBED_UNCONNECTED", "facebookAppId": "...", "facebookConfigId": "..." }
{ "status": "CONNECTED", "phoneNumber": "+39 333 123 4567", "wabaId": "...", "phoneNumberId": "..." }List approved templates
GET /api/v1/templates?externalCustomerId=user_123
x-fusionwa-api-key: fwa_live_...
x-fusionwa-api-secret: <your-secret>
# Response
{
"status": "success",
"templates": [
{ "name": "booking_confirmation", "status": "APPROVED", "language": "it", "category": "UTILITY", "variableCount": 2 }
]
}Download received images
Call GET /api/v1/media/{mediaId}?externalCustomerId=YOUR_CUSTOMER_ID from your backend with both x-fusionwa-api-key and x-fusionwa-api-secret. Store image.id from incoming, echo or history payloads when available; the message ID is not a media ID.
The endpoint returns JPEG, PNG or WebP bytes (maximum 5 MiB), after checking the application, customer and connected phone. Serve these bytes through your own authenticated, tenant-scoped endpoint. Never expose the secret in frontend code. Responses are private and not cached.
Media can expire or become unavailable; this endpoint is not a permanent archive and cannot recover old messages whose media ID was not saved. Limit: 120 requests per minute per application. See the OpenAPI specification for error responses.
Webhooks
FusionWA forwards every WhatsApp event to your endpoint in real time. Configure the URL in Applications → Webhook in the dashboard.
Zero storage: payloads are forwarded only, never stored.
Payload structure
{
"type": "message",
"from": "+39 02 1234567",
"customerId": "user_123",
"timestamp": "2025-01-15T10:30:00Z",
"message": {
"id": "wamid.abc...",
"type": "text",
"text": { "body": "Hello" }
}
}Event types
messageIncoming message from a customerstatusMessage delivery status update (sent / delivered / read)template_statusMeta template approval status changeReceive events in your backend
// Express
app.post("/webhook/whatsapp", express.json(), (req, res) => {
const { type, from, customerId, message } = req.body;
if (type === "message" && message?.type === "text") {
console.log(`[${customerId}] ${from}: ${message.text.body}`);
// store, process, reply...
}
res.sendStatus(200); // respond 200 within 10s or the webhook is retried
});WhatsApp Templates
Templates enable proactive outbound messages (notifications, reminders, confirmations). They must be approved by Meta before use.
Create and submit a template
POST /api/v1/templates
{
"customerId": "user_123",
"name": "order_confirmed",
"category": "UTILITY",
"language": "it",
"components": [
{
"type": "BODY",
"text": "Your order {{1}} is confirmed. Delivery: {{2}}."
}
]
}The template is submitted to Meta for review. Status becomes APPROVED typically within a few hours. You receive a template_status webhook event when the status changes.
Error Reference
200Success400Invalid request body401Missing or invalid API Key403App revoked or customerId not authorized404Customer not found or not connected422Validation error (see response body)429Rate limit exceeded500Internal error — retry with backoffFor AI Coding Assistants
Use this block as initial context in your prompt when integrating FusionWA with Claude Code, Codex, Cursor, or GitHub Copilot:
# FusionWA Integration Context
Read https://fusionwa.com/llms.txt for the full machine-readable specification.
## SDK Widget
<script src="https://fusionwa.com/sdk/v1.js"></script>
<div id="fusionwa-widget"></div>
<script>
FusionWA.init({ apiKey, customerId, containerId })
</script>
## REST API
Base URL: https://fusionwa.com/api/v1
Auth: X-FusionWA-API-Key: fwa_live_...
POST /api/v1/messages/send
body: { to, templateName, languageCode, components[] }
returns: { messageId }
GET /api/v1/widget/status?customerId=
returns: { status: "INACTIVE"|"CONNECTED", phoneNumber }
GET /api/v1/templates?customerId=
returns: [{ name, status, language, category }]
## Webhooks
Configure URL in dashboard. Payload: { type, from, customerId, timestamp, message }
Respond 200 within 10s. type: "message" | "status" | "template_status"
## Security rules
- apiKey: client-safe (SDK only)
- API Secret: server-only (never expose)
- customerId: your internal ID, any unique string
- Do NOT store messages — forward to your own DB if needed
- Do NOT invent endpoints — use only the documented ones aboveDownload the machine-readable version: /llms.txt