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

Step 1: Connect your number

  1. In YCloud’s WhatsApp accounts, find which WABA owns the number, then confirm its owner in Meta Business Settings. If YCloud or an agency owns it, only they can release the number.
  2. In WhatsApp Manager, check the WABA for other numbers, templates, or assets you still need.
  3. Confirm you are an admin of the owning Business Portfolio, which Meta requires for removal.
  4. Under Account tools → Insights, confirm the number has not sent a paid message in the last 30 days.
  5. Turn off two-step verification on the number, or re-registration will ask for a PIN.
  6. Remove the phone number from the WABA.
  7. Wait about five minutes.
  8. In Kapso, start embedded signup. Share your existing WABA, or create one when the flow asks.
  9. Recreate your templates if you created a new WABA (see Step 5). Wait for Meta review.
The number stops sending after step 6, and on a new WABA it can send templates again once Meta approves them. Plan the migration accordingly. See Connect WhatsApp for the signup flow. Migrating does not touch the old WABA. If you retire it later and Meta blocks removal over a pending balance, YCloud may still have a credit line attached, which Meta Direct Support has to clear. If the reconnect fails, see coexistence troubleshooting and bring your own SIM 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? Build against a sandbox number while YCloud still carries production traffic. Create a session for your test phone, then send the 6-character code from WhatsApp.

Step 2: Get your phone number IDs

Store the mapping from +E164 to phone_number_id. It replaces every "from": "+1555..." in your send code. YCloud takes wabaId in the request body for templates and flows. Kapso takes it in the path, as in POST /{waba_id}/message_templates. Templates belong to the WABA in both, so every number on that WABA can send them.

Step 3: Update message sending

YCloud has two send endpoints. POST /v2/whatsapp/messages queues the message and returns accepted, and POST /v2/whatsapp/messages/sendDirectly submits to Meta and waits. Kapso has one: POST /{phone_number_id}/messages. It submits to Meta synchronously and returns the wamid, so it behaves like sendDirectly. If your code branches between the two YCloud endpoints, both branches collapse into this one. Three things change in every call:
  • from moves out of the body and into the path, as phone_number_id.
  • messaging_product: "whatsapp" is required.
  • to is written as bare digits by convention, but your existing E.164 values work unchanged. Kapso forwards the request body to Meta byte for byte, and Meta accepts the leading +.
The content object itself does not change. YCloud passes Meta’s shapes through, and so does Kapso.
Business-initiated sends, outside the 24-hour window.YCloud:
Kapso:
The template object is identical. externalId becomes biz_opaque_callback_data, capped at 512 characters and echoed back on status webhooks. See Simple text templates.
YCloud returns its own object ID on send, and the Meta wamid only later, on the sent status webhook. Kapso returns the wamid immediately:
If your database keys messages on YCloud’s id, switch that column to the wamid. Everything that took a wamid on YCloud (context.message_id, mark-as-read, reactions) keeps taking one. The TypeScript SDK wraps all of this, so you do not have to write the envelopes by hand.

Step 4: Update webhooks

YCloud webhooks are account-wide: one endpoint receives every event for every number, and you route in your own handler. Which field carries your number depends on the event: Kapso registers webhooks per phone number, so that routing disappears: the endpoint you register only ever receives that number’s events.
You choose the signing secret. YCloud generates one and returns it on create. Account-level events (a WABA ban, a number offboarded, a customer finishing a setup link) arrive on project webhooks instead. You configure those once for the whole project.

Event mapping

YCloud dispatches one event for delivery and asks you to switch on whatsappMessage.status. Kapso dispatches one per status, named in the X-Webhook-Event header. The switch moves from the body to the header.

Account and number events

whatsapp.business_account.updated carries seven updateEvent values, on project webhooks: Since 2026-06-10 YCloud sends partner removal as business_account.deleted instead, so handle both. Its removedReason, removedInitiatedBy, and removedTime are optional, so their absence does not prove a real deletion.

Raw Meta webhooks

Kapso can also forward every Meta webhook for a number, unreshaped. Register a second webhook with "kind": "meta":
Payloads are Meta’s, so this needs its own handler. See Webhooks overview.

Field mapping

Inbound, from whatsappInboundMessage to Kapso’s whatsapp.message.received: Outbound, from whatsappMessage to the status events: from is not always present. WhatsApp can identify a contact with business_scoped_user_id instead. See business-scoped user IDs.

Signature verification

YCloud signs the timestamp and the body together, and sends both in one header. Kapso signs only the body. YCloud:
Kapso:
Both need the raw bytes, so whatever you did to capture rawBody still applies. The freshness check does not carry over: Kapso signs no timestamp, so the tolerance you tuned against YCloud’s t has nothing to bind to. See Security for Python and Ruby.

Delivery behavior

See Advanced for buffering and ordering, and Security for verification in Python and Ruby.

Step 5: Templates

Same components, different addressing. YCloud takes wabaId in the body, Kapso takes it in the path. YCloud:
Kapso:
The rest of the lifecycle maps directly: Create and edit are one endpoint in Kapso. hsm_id is a query parameter, not a body field: add ?hsm_id=... to update instead of create. Delete also identifies the template by query string, taking either ?name=... or ?hsm_id=.... Templates belong to the WABA. If the number stayed on a WABA you already owned, they are still there. If it landed on a new one, recreate them and wait for review. Rebuilt them in WhatsApp Manager? Pull them in from WhatsApp → Templates → Sync from WhatsApp. See Template lifecycle.

Contacts and opt-outs

YCloud stores contacts in its own CRM, with tags, custom attributes, owners, and source attribution. Kapso stores a smaller contact record and a free-form metadata object:
Export your YCloud unsubscriber list before you close the account and keep suppressing those contacts on your side. See Marketing opt-outs.

Multi-tenant setups

If you message on behalf of your own customers, each one becomes a Kapso customer that connects its own number through a setup link, instead of you onboarding WABAs on their behalf:
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. Migrate one customer at a time.

Bulk sends

YCloud’s queueing endpoint absorbs bursts, so bulk sends there are often just a fast loop over POST /v2/whatsapp/messages, whatever the message type. Kapso’s send endpoint is synchronous, and what replaces the loop depends on what you were sending. Approved-template campaigns become broadcasts. whatsapp_template_id is required on create, so a broadcast always sends one approved template, of any category. The one restriction is that authentication templates cannot go to BSUID recipients:
Kapso paces broadcasts internally to stay inside Meta’s throughput limits, so you do not throttle them yourself. On a marketing broadcast, recipients who stopped marketing are marked suppressed and skipped, which covers what filterUnsubscribed did per send. The guard checks the template category first, so utility and authentication broadcasts are not subject to marketing opt-outs at all. They can still fail per recipient for other reasons, including the BSUID restriction above. Bulk text, media, and interactive sends have no broadcast equivalent, because those are session messages rather than templates. Keep your own durable queue in front of POST /{phone_number_id}/messages for them, and pace it yourself against your rate limit. POST /{id}/schedule sends later. Stopping depends on what state the broadcast is in: POST /{id}/cancel returns a scheduled broadcast to draft, and it does nothing for one that is already sending. To stop a send in flight, patch the status:
Pending recipients stay pending and no new sends start. Campaigns built in the YCloud console move to broadcasts, with CSV upload for the recipient list.

Billing

YCloud runs on a prepaid balance: you top up, YCloud pays Meta, and BALANCE_INSUFFICIENT stops sends. Kapso offers the same shape, or direct Meta billing: Choose the mode when the WABA is connected. See Meta message billing and pricing.

Feature map

Things Kapso adds:
  • Automatic voice-note transcription on inbound audio
  • Functions on Cloudflare Workers, as workflow steps, agent tools, or plain endpoints
  • Findings, which reads ended conversations with AI and groups the recurring problems
  • Conversation lifecycle webhooks, so you can act when a conversation goes quiet or ends

What does not map

  • SMS, email, voice, and Verify. YCloud’s /v2/sms, /v2/emails, /v2/voices, and /v2/verify/verifications have no Kapso equivalent. Kapso is WhatsApp only. Keep a YCloud account or another provider for those channels.
  • Contact attribute definitions, tags, and owners. Contact metadata is schemaless.
  • Balance API. No GET /v2/balance. Credits live in project settings.

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.
Message history does not transfer, and neither do contacts or unsubscribers. YCloud keeps them behind its own APIs. Export what you need before you close the account.

Troubleshooting

Node.js example

The example below is scoped to what changes when you move off YCloud. It is not a hardened receiver: deduplication, retry handling, and buffering are the same on Kapso whatever you migrated from, so they live in Advanced and Security. Read those before this handler takes production traffic.

Need help