Skip to main content
If you’re building WhatsApp into your own product, each customer brings their own Business Account. LazyApp’s tenant boundary for this is the platform customer: one isolated workspace per customer, their connection inside it, and your database holding the mapping via external_id. This page covers the core model. Once it’s in place, the recipes show how to build features on top without fighting rate limits:

Tenant messaging

Retry-safe sends for every customer: idempotency, templates, scheduling

Tenant usage dashboards

Show each customer their consumption and cost from the usage API

Tenant inbox

Conversations per customer: webhook-first, replies, embeds
Requests flow one way, events flow back — and your database is what connects the two: Your own workspace stays separate. Create one platform customer per of their customers alongside it.
Building a product, or reselling LazyApp? This section is for platform teams: you call /v1/platform/* from your own app, and your platform wallet pays ₹999 a month per connected customer number. If you want to put your brand on the LazyApp console and charge businesses your own monthly price, without writing code, see Resellers.

Step 1: Create a customer per tenant

When a customer signs up in your app, create their LazyApp customer and store the returned id (or just keep using your own external_id — LazyApp accepts either).
external_id is your own account id, so you never need a mapping table. Look them up later with GET /v1/platform/customers?external_id=acct_8812. Creating a customer costs nothing. What you pay LazyApp is ₹999 a month for each customer number that connects, covered in How platform billing works.
markup_bps, pricing_mode, category_markups and platform_fee are no longer stored or returned. LazyApp adds nothing to Meta’s rates, so there is no per-customer markup to configure. A request that still sends them succeeds, and the values are ignored.
See Create a customer for all fields.

Step 2: Let them connect WhatsApp

Create a setup link so they connect through Meta’s Embedded Signup. You never handle their credentials.
Hand url to your customer — email it, or put it behind a Connect WhatsApp button. The host is LazyApp’s domain unless you set a public connect host under Branding. That value is an origin (https://connect.yourapp.example). Point it at LazyApp so /connect/{token} resolves, and the page shows your brand name, logo, and accent. Meta’s own signup screen still says Facebook. Subscribe to customer.connected to learn about new connections server-side. Platform deliveries include a customer envelope with your external_id:
Also handle setup_link.failed and connection.attention_required / connection.disconnected so you can prompt a reconnect. The whole onboarding flow, end to end: Do not trust the redirect alone — it is UX only. Confirm from the webhook. Details in setup links.

Step 3: Send on their behalf

Two patterns. Pick one:

Mint a scoped key

That key can only see that customer’s workspace. Omit scopes to grant the defaults for a customer-scoped key.

Or act with the platform key

X-LazyApp-Customer accepts public_id, uuid, or external_id. The key needs customers:act (send only) or customers:write (full management). See Authentication. The messaging recipe covers idempotency, templates, and scheduling: Tenant messaging.

Step 4: Route webhooks back to the right customer

Webhook endpoints are configured once on your platform workspace, not per customer. Register one endpoint and route internally. Every event that originated in a customer’s workspace is also delivered to your platform endpoints, with a customer envelope: See Webhooks for delivery, retries, and signature verification, and Tenant inbox for a full handler sketch.

Rate limits with many tenants

One platform API key is enough for your whole integration. LazyApp limits requests per key, not per customer — see rate limits for the ceiling and the headers that report it. Meta separately caps how many unique contacts a number may message in 24 hours; that limit is per connection, reported on GET /v1/capabilities. That budget serves all your tenants together, which has three practical consequences:
  • Prefer webhooks over polling. Most per-tenant “is there anything new?” traffic disappears when webhooks push events to you.
  • Run background work as one smooth queue. A sync worker with a small concurrency cap uses the budget steadily. Per-tenant cron jobs that all fire at :00 create bursts.
  • Fairness between tenants is yours to enforce. LazyApp limits your key, not your customers — if one tenant triggers a huge burst, queue it so it cannot starve everyone else.
When you get a 429, back off and retry with the same Idempotency-Key. Handle 402 distinctly. It is a billing state, not a transient error: the customer is suspended, its spending limit is reached, or a wallet that has to pay for the send is empty. Alert someone; retrying will not help.

Monitor connection health

WhatsApp credentials fail: Meta reviews, quality issues, or a customer reconnects elsewhere. Build the reconnect loop up front:
  1. Subscribe to connection.attention_required and connection.disconnected — platform deliveries include the customer envelope.
  2. Prompt that customer to reconnect with a new setup link (allowed_connection_type: "reconnect").
  3. As a safety net, periodically call GET /v1/capabilities with X-LazyApp-Customer (or a scoped key) to catch anything a webhook missed.

How platform billing works

A platform team pays LazyApp ₹999 a month for each connected customer number, debited from your platform wallet. Creating customers and minting keys cost nothing, and so do sends on customer-paid numbers. Add money to the wallet from Billing in your platform workspace; see Wallets. In return your team is on the Platform plan: every feature, including the API, webhooks, automations, Flows, payments and catalog, with no caps on members, numbers or broadcast sends. Each managed customer workspace inherits your plan, so a customer never hits a plan limit that your team does not. The console marks the wallet low once it holds less than one month of your number cost.

Who pays Meta

LazyApp adds 0% to Meta’s message rates, and platform customers carry no markup. Who pays Meta for a customer’s messages is set once per WhatsApp Business Account, by meta_billing_mode on the setup link: Customer-paid numbers are the default because they keep you out of the money flow: Meta invoices your customer, and your wallet only covers the ₹999 per number. See Meta message billing for how Meta charges.

Billing modes

billing_mode decides whose wallet takes a charge when there is one — that is, only for messages LazyApp pays Meta for: Set spending_limit_cents to cap what a customer’s sends may cost in a month, and usage_alert_cents to receive customer.usage_alert before they reach it. Both measure total_charge, so on a customer-paid number they never trigger. Read consumption with GET /v1/platform/customers/{customer}/usage. You bill your own customers however you like, outside LazyApp.

Offboarding a customer


Embedding UI

Rather than rebuilding an inbox, drop LazyApp components into your product with short-lived, origin-locked tokens. See embedded components.