The Dualhook Platform API lets your backend create a one-time co-branded WhatsApp onboarding URL for any tenant in 10 lines of code. Your tenant clicks Connect WhatsApp, completes Meta's Embedded Signup, and your event endpoint receives a signed onboarding.completed payload with the new connectionId.
Run in Postman / OpenAPI
Open the public Postman workspace: Dualhook Platform API on Postman. Fork the workspace into your own, set the DUALHOOK_API_KEY collection variable to your dh_live_… key, and run any request. The Create onboarding session request captures the returned sessionId into a collection variable so the next call (Get onboarding session) just works.
Prefer to import locally? Grab the JSON: dualhook-platform-api.postman_collection.json. The OpenAPI 3.1 source for the collection lives at openapi/platform-api.yaml.
What this does
POST /api/v1/onboarding/sessions returns a one-hour-valid onboardingUrl you can render inside your app. When the tenant finishes Meta's Embedded Signup, Dualhook exchanges the OAuth code, subscribes the Meta webhook to the URL you supplied, and fires an HMAC-SHA256 signed onboarding.completed event to your event endpoint.
Create your first session
const r = await fetch("https://dualhook.com/api/v1/onboarding/sessions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.DUALHOOK_API_KEY}`,
"Content-Type": "application/json",
"Idempotency-Key": crypto.randomUUID(),
},
body: JSON.stringify({
tenantId: customer.id,
tenantName: customer.name,
successRedirectUrl: `https://app.example.com/done?cust=${customer.id}`,
failureRedirectUrl: `https://app.example.com/error?cust=${customer.id}`,
cancelRedirectUrl: `https://app.example.com/cancel?cust=${customer.id}`,
webhookOverrideUrl: "https://api.example.com/whatsapp",
webhookVerifyToken: process.env.MY_WEBHOOK_VERIFY_TOKEN,
}),
});
const { onboardingUrl } = await r.json();
return redirect(onboardingUrl);
The response also includes sessionId and expiresAt. Sessions are valid for 1 hour by default (pass expiresInSeconds, 300–86400, to override). Idempotency-Key is optional but recommended — reusing the same key with the same body returns the same session. Note that Dualhook preflights the webhookOverrideUrl with a simulated Meta verification GET at creation time — see onboarding sessions for the endpoint requirements and the skipWebhookPreflight escape hatch.
After the user completes onboarding
successRedirectUrl will receive ?sessionId=…&status=completed. Your event endpoint (configured in the dashboard) will receive a signed onboarding.completed payload with connectionId, wabaId, phoneNumberId, tenantId, and your round-tripped metadata.
To fetch the Cloud API access token for that connection:
POST /api/v1/connections/<connectionId>/reveal-secrets
{ "secretTypes": ["access_token"] }
The response carries Cache-Control: no-store. Every reveal is recorded in the audit log against the API key that called it.
Next steps
- Onboarding sessions — full request/response, idempotency, redirect URL whitelist, and the WABA-scoped webhook constraint.
- Event webhooks — every lifecycle event you'll receive and the retry schedule.
- Webhook signatures — verify
X-Dualhook-Signatureover the raw body. - Reveal access tokens — token reveal contract and audit trail.
- Errors — every error code you may encounter.
- Platform API overview