@kapso/sdk
v0.1.0
Published
Framework-independent browser SDK for onboarding WhatsApp customers with Kapso.
Readme
@kapso/sdk
Framework-independent TypeScript SDK for onboarding your customers to WhatsApp through Kapso.
It handles Meta Embedded Signup, sends the short-lived authorization code to Kapso, and resolves only after the WhatsApp connection has been durably processed.
Install
bun add @kapso/sdknpm install @kapso/sdkThe package works with plain TypeScript and does not require React, Vue, or another UI framework.
Quick start
1. Create a setup link on your server
Use your Kapso Platform API key only on your backend:
const response = await fetch(
`https://api.kapso.ai/platform/v1/customers/${customerId}/setup_links`,
{
method: "POST",
headers: {
"X-API-Key": process.env.KAPSO_API_KEY!,
"Content-Type": "application/json",
},
body: JSON.stringify({
setup_link: {
allowed_connection_types: ["dedicated"],
allowed_origins: ["https://app.yourcompany.com"],
meta_billing_mode: "partner_managed",
provision_phone_number: false,
},
}),
},
);
if (!response.ok) throw new Error("Could not create the Kapso setup link");
const { data: setupLink } = await response.json();
// Send only setupLink.token to your frontend.Never expose your Kapso Platform API key in browser code. The setup-link token is temporary, revocable, origin-restricted, and single-use after successful onboarding.
2. Connect WhatsApp in the browser
Create the instance when the page renders. It resolves after Kapso and Meta are ready, allowing
connect() to open Embedded Signup directly from the user's click:
import { createWhatsAppOnboarding } from "@kapso/sdk";
const whatsapp = await createWhatsAppOnboarding({
token: setupLinkToken,
});
connectButton.onclick = async () => {
const connection = await whatsapp.connect();
onConnected(connection);
};Create the instance during page initialization and enable your connect button after the promise resolves. Keep loading, cancellation, and error presentation in your own UI layer.
connect() coalesces concurrent calls on the same instance, opens one Meta popup, and resolves to:
type WhatsAppConnection = {
whatsappConfigId: string;
wabaId: string;
phoneNumberId: string;
displayPhoneNumber?: string;
};Create a new setup-link token after a successful connection. To retry a cancelled or failed flow, create a fresh SDK instance with the still-valid setup-link token.
Phone-number options
The setup-link creator chooses the flow. The browser cannot override it.
Customer-owned number
{
"allowed_connection_types": ["dedicated"],
"provision_phone_number": false
}Kapso-provisioned number
{
"allowed_connection_types": ["dedicated"],
"provision_phone_number": true,
"phone_number_country_isos": ["US"]
}Kapso selects and pins eligible preverified inventory or a carrier number on the server. The SDK never accepts an arbitrary number or inventory identifier from browser code.
WhatsApp Business App coexistence
{
"allowed_connection_types": ["coexistence"],
"provision_phone_number": false
}The initial SDK supports exactly one connection type per setup link.
Billing and Multi-partner Solutions
meta_billing_mode, Meta credentials, the Embedded Signup configuration, and any Multi-partner
Solution are selected and pinned when Kapso bootstraps the setup link. The browser cannot replace
them.
Both modes are supported when the project is eligible:
customer_managed: the customer pays Meta directly.partner_managed: the project's Kapso balance pays Meta message fees.
Cancellation and cleanup
Pass an AbortSignal to cancel the flow from your application:
const controller = new AbortController();
const whatsapp = await createWhatsAppOnboarding({
token: setupLinkToken,
signal: controller.signal,
});
controller.abort();Or call whatsapp.destroy() when unmounting the page. Both stop polling and remove browser event
listeners. They reject pending connect() work with user_cancelled.
Errors
All expected failures are WhatsAppOnboardingError instances with a stable code, safe message,
and retryable boolean. Raw Meta responses, authorization codes, credentials, and tokens are never
included.
import { WhatsAppOnboardingError } from "@kapso/sdk";
try {
await whatsapp.connect();
} catch (error) {
if (
error instanceof WhatsAppOnboardingError &&
error.code !== "user_cancelled"
) {
showConnectionError(error);
}
}| Code | Meaning |
| --- | --- |
| user_cancelled | The user closed or cancelled Meta signup, or the app cancelled the SDK. |
| invalid_setup | The setup token or server-pinned setup is invalid. |
| setup_expired | The setup link or onboarding attempt expired. |
| origin_not_allowed | The page origin is not in the setup link's exact allowlist. |
| unsupported_setup | The setup link requests a flow the SDK does not support. |
| phone_provisioning_unavailable | Kapso cannot currently provide an eligible number. |
| phone_provisioning_requires_authorization | The project needs a payment or hosted authorization step. |
| meta_sdk_unavailable | Meta's browser SDK did not load or initialize. |
| meta_authorization_failed | Meta did not return a usable authorization code. |
| processing_failed | Kapso could not finish the durable backend workflow. |
| processing_timeout | Processing exceeded the SDK's bounded polling window. |
Domain requirements
allowed_originsmust contain the exact HTTPS origin running the SDK, including a non-default port when applicable. Paths and wildcards are not accepted.- If the project uses your Tech Provider Meta app, register the frontend domain in that Meta app's Facebook Login for Business / JavaScript SDK settings.
- Do not put the setup token in a URL. Deliver it in your authenticated application response and pass it directly to the SDK.
Test a real setup link locally
The repository includes a vanilla Vite example:
bun install
VITE_KAPSO_SETUP_TOKEN=<setup-link-token> bun run exampleProduction setup links require an HTTPS origin. Expose the Vite server through an HTTPS development
tunnel, add that exact origin to allowed_origins, and pass its hostname to the example's exact
Vite allowlist:
VITE_KAPSO_SETUP_TOKEN=<setup-link-token> \
VITE_ALLOWED_HOST=<tunnel-hostname> \
bun run example --host 0.0.0.0Register the domain in the relevant Meta app. Then open the tunnel URL and click Connect WhatsApp.
Development
bun install
bun run checkcheck runs ESLint, TypeScript, the unit suite, and the reproducible ESM/CJS build. The output
includes declarations and source maps in dist/.
