WhatsApp

Onboard your customers' WhatsApp numbers

Send each of your customers a setup link that connects their WhatsApp number into their namespace, then react to the connection in a webhook.

If you run a platform with a namespace per customer, your customers need to connect their own WhatsApp numbers without a Samva account. A setup link does that: you create one for a namespace, send its URL to your customer, and they connect their number on a Samva-hosted page through Meta's signup window. The number lands in the link's namespace, and Samva sends you a whatsapp.number.connected webhook event that carries the metadata you attached to the link, so you know which customer connected.

Create the link with a key that can manage WhatsApp accounts. A key confined to a namespace creates links only for that namespace.

curl -X POST https://api.samva.dev/v1/whatsapp/setup-links \
  -H "X-API-Key: samva_sk_live_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "namespaceId": "ns_3xk9mvt4znw8rh7q",
    "redirectUrl": "https://platform.example.com/settings/whatsapp",
    "metadata": { "customerId": "cus_123" }
  }'
samva whatsapp setup-links create --namespace ns_3xk9mvt4znw8rh7q \
  --redirect-url https://platform.example.com/settings/whatsapp \
  --metadata customerId=cus_123

You can also create one from the Setup links section of the dashboard WhatsApp page.

FieldMeaning
namespaceIdThe namespace the connected number joins.
redirectUrlOptional. Where the hosted page sends your customer after their number connects. An absolute https URL.
metadataOptional. Your own string labels, such as your customer's id. Returned on the link and on the whatsapp.number.connected event.
expiresAtOptional. When the link stops working. It defaults to 7 days ahead and can be at most 30 days ahead.

Metadata holds at most 50 keys, with keys up to 64 characters and values up to 512 characters.

The response is the link plus its url:

{
  "id": "wasl_8h2kq9vt4znw3rm7",
  "namespaceId": "ns_3xk9mvt4znw8rh7q",
  "status": "pending",
  "redirectUrl": "https://platform.example.com/settings/whatsapp",
  "metadata": { "customerId": "cus_123" },
  "expiresAt": "2026-10-24T10:30:00.000Z",
  "businessAccountId": null,
  "completedAt": null,
  "revokedAt": null,
  "createdAt": "2026-10-17T10:30:00.000Z",
  "updatedAt": "2026-10-17T10:30:00.000Z",
  "url": "https://samva.dev/connect/whatsapp#token=..."
}

The url is the link's credential and appears only in this response. Samva keeps a digest of it, so it cannot show it again. If you lose it, revoke the link and create another.

Send it to your customer

Send the url to your customer through your own channel: your onboarding email, your app, or a message from your team. Your customer opens it, signs in with Meta, and chooses or creates their WhatsApp Business Account and phone number. They need no Samva account. A link connects one number and then stops working.

When the number connects, Samva stores it in the link's namespace, as if it had been connected from the dashboard, and sends your customer to redirectUrl when you set one.

The link acts on behalf of the team member who created it. If that member leaves your organization, their links stop working; create new ones from a current member.

A link that was used, revoked, or has expired answers your customer with a page saying so, and the API reports it as 410. A new number connects as pending until Samva registers it with Meta; see Status, quality, and limits.

Receive the connection

Every number that connects sends a whatsapp.number.connected event, whether it connected from the dashboard or through a setup link. The event catalog describes delivery and signing. An endpoint filtered to a namespace receives the event for its own namespace.

{
  "type": "whatsapp.number.connected",
  "timestamp": "2026-10-17T11:02:41.318Z",
  "data": {
    "organizationId": "org_5nq7vt3xkm2w9h4r",
    "namespaceId": "ns_3xk9mvt4znw8rh7q",
    "businessAccountId": "waba_7vt4znw8rh3xk9mq",
    "phoneNumber": "+16175550123",
    "phoneNumberId": "109876543210987",
    "whatsappBusinessAccountId": "100123456789012",
    "displayName": "Acme Salon",
    "verificationStatus": "pending",
    "reconnected": false,
    "setupLink": {
      "id": "wasl_8h2kq9vt4znw3rm7",
      "metadata": { "customerId": "cus_123" }
    }
  }
}
FieldMeaning
namespaceIdThe namespace the number joined, or null for a number connected at organization level.
businessAccountIdThe Samva id of the connected account; use it with /v1/whatsapp/business-accounts.
phoneNumberId, whatsappBusinessAccountIdMeta's ids for the number and its WhatsApp Business Account.
verificationStatusThe account's status when the number connected. A new number is pending until Samva registers it.
reconnectedtrue when the number was already connected and this signup renewed access to it.
setupLinkThe link the number connected through, with its id and your metadata; null when it connected from the dashboard.

Match setupLink.metadata to your own customer record, then mark that customer connected. Handle the event idempotently; deliveries can repeat.

ActionRESTCLI
ListGET /v1/whatsapp/setup-linkssamva whatsapp setup-links list
GetGET /v1/whatsapp/setup-links/{linkId}samva whatsapp setup-links get <id>
RevokePOST /v1/whatsapp/setup-links/{linkId}/revokesamva whatsapp setup-links revoke <id>

List accepts namespaceId and status, and pages by cursor. A link's status is one of:

StatusMeaning
pendingThe link can still connect a number.
completedA number connected through it; businessAccountId names the account.
revokedYou revoked it before it was used.
expiredIt passed expiresAt unused.

Revoke a pending link when you sent it to the wrong person or no longer need it. Revoking a link that is already completed, revoked, or expired answers 410. A key confined to a namespace lists, reads, and revokes only that namespace's links.

Related documentation

On this page