Skip to main content
Migrate your WhatsApp numbers from Twilio to Kapso.

Step 1: Connect your number

  1. In WhatsApp Manager, check the WABA for other numbers, templates, or assets you still need.
  2. Remove the phone number from the WABA.
  3. In Meta Business Settings, open Accounts → WhatsApp accounts.
  4. If the old WABA sits in your Business Portfolio, remove it.
  5. Wait about five minutes.
  6. In Kapso, start embedded signup. Create a new WABA when the flow asks.
  7. Recreate your templates on the new WABA (see Step 5). Wait for Meta review.
The number stops sending after step 2, and it can send templates again once Meta approves them on the new WABA. Plan the migration accordingly. See Connect WhatsApp for the signup flow. If Meta blocks the WABA removal over a pending balance, your old provider may still have a credit line attached to it. Meta Direct Support has to clear that. A different number on a new WABA unblocks you in the meantime. If the reconnect fails, see coexistence troubleshooting. You can also start on a fresh number. Instant setup gives you a pre-verified US number, with no SMS verification step.
Testing first? The sandbox replaces Twilio’s join <code> flow. Create a session for your test phone, then send the 6-character code from WhatsApp. You can then send and receive without a production number.

Step 2: Get your phone number IDs

Store the mapping from whatsapp:+E164 to phone_number_id. Two IDs address different things: Templates belong to the WABA, not to a number, so every number on that WABA can send them. That is why the template endpoints take the WABA ID in the path, as in POST /{waba_id}/message_templates.

Step 3: Update message sending

For every message type, Kapso uses one endpoint: POST /{phone_number_id}/messages. The type field says which kind of message you are sending, and a field of that same name carries the content. A text message sets type: "text" and puts the body in text.
Business-initiated sends, outside the 24-hour window. ContentSid becomes the template name, ContentVariables becomes Meta’s components array.Twilio:
Kapso:
Parameters are positional and must match the placeholder order. Named parameters work too. See Simple text templates.
The TypeScript SDK wraps all of this, so you do not have to write the envelopes by hand.

Step 4: Update webhooks

Kapso posts JSON and expects a 200. There is no TwiML, so auto-replies move into your handler or into a workflow. Register per phone number:
For connection lifecycle events (a customer finishing a setup link, Meta disabling a WABA), use project webhooks instead. You configure those once for the whole project.

Field mapping

conversation threads the messages for you, but it does not track the 24-hour window. A send can fail with 131047 while conversation.status is active. Read conversation.kapso.last_inbound_at, or handle the rejection and fall back to a template. from is not always present. WhatsApp can identify a contact with business_scoped_user_id instead. See business-scoped user IDs.

Signature verification

Twilio signs the request URL plus every form field, so verification needs all of them. Twilio’s helper assembles them for you. Kapso signs only the request body. Verification is one HMAC over the bytes you received. Twilio:
Kapso:
No URL goes into the hash, so your endpoint can move or sit behind a proxy without breaking verification.

Delivery behavior

Delivery is at-least-once. Dedupe on X-Idempotency-Key. See Advanced for buffering and ordering, and Security for verification in Python and Ruby.
Do you parse raw Meta payloads elsewhere? Register the webhook with "kind": "meta" and Kapso forwards Meta’s exact payload with no reshaping.

Step 5: Templates

Twilio needs two calls: create the content, then request WhatsApp approval. Kapso submits on create. Twilio:
Kapso:
The path takes the WABA ID, not the phone number ID. If you build templates in WhatsApp Manager, pull them into Kapso from WhatsApp → Templates → Sync from WhatsApp. See Template lifecycle.

Multi-tenant setups

Twilio subaccounts become customers, and each customer connects their own number through a setup link instead of you provisioning a sender per subaccount:
Send your customer the returned url. They log in with Facebook and connect in about five minutes. You then get whatsapp.phone_number.created on your project webhook, with the customer.id and phone_number_id. See Onboard customers and Connection detection. One API key covers every customer, so there is no per-subaccount credential juggling.

Bulk sends

If you loop over recipients yourself, or drive bulk sends from Studio, use broadcasts instead. Create, add recipients with per-recipient template parameters, send, poll:
Kapso paces broadcasts internally to stay inside Meta’s throughput limits, so you do not throttle them yourself. POST /{id}/schedule sends later, POST /{id}/cancel stops one in flight.

Keep your Twilio account for numbers

You do not have to leave Twilio to leave Twilio’s WhatsApp API. Point Kapso at your Twilio credentials and it provisions new numbers into your Twilio account, billed to you. You choose the countries, and each one can keep a pool of reusable pre-verified numbers. This covers provisioning, not the numbers your Twilio WhatsApp senders already use. Those still follow Step 1. This is an Enterprise feature, or a paid add-on on other plans. See Provide local numbers.

Feature map

Things Kapso adds:

What does not map

  • Messaging Services. No sender pools, sticky sender, or geomatch. You send from a specific phone_number_id.
  • TwiML. Auto-replies move into your webhook handler or a workflow.
  • Link shortening and click tracking.
  • Conversation tags. Organize in the inbox UI, not the API.

Cutover

Migrate one number at a time. A number’s WhatsApp registration and webhook routing move as a unit, so there is no gradual split per number. One thing needs no migration. Meta bills message charges against the WABA on either platform, per delivered template message, at category and market rates. See pricing.
Message history does not transfer. Twilio keeps it in its Messages resource. Export what you need before you close the account.

Troubleshooting

Node.js example

Need help