WhatsApp API Platform

API Reference

The full Embed SDK surface — Embed.render, Embed.init, the instance handle, the declarative data-embed form, and event names.

The loader defines one global, Embed. TypeScript declarations ship at embed.d.ts next to the loader.

Embed.render(product, options)

Mounts a surface and returns an instance, or null if it can't mount (missing required option, target not found, unknown product). The reason is logged to the console.

var instance = Embed.render("chatbot", {
  target: "#embed",
  chatbotId: "cb_123",
  authToken: "<jwt>",
});

product — one of "chatbot", "template", "broadcast", "broadcastList", "teamChat". Get the list at runtime with Embed.products().

options — the common options plus any surface-specific options:

SurfaceExtra options
chatbotchatbotId (required)
broadcastfromBroadcast, statuses, redirectUrl (all optional)
broadcastListshowCreateButton (optional)
teamChatagentId (optional)
template

Instance

The object returned by render. Also exposed as element._embed on declaratively-mounted elements.

MemberSignatureDescription
productstringThe surface name this instance was created for.
iframeHTMLIFrameElementThe mounted iframe.
on(type, handler) => instanceSubscribe to an event. Chainable.
once(type, handler) => instanceSubscribe for a single firing.
off(type, handler?) => instanceRemove a handler, or all handlers for type when omitted.
send(type, payload?) => instancePost a message to the iframe (forward-compatible; consumed where supported).
destroy() => voidRemove the iframe and detach all listeners.
instance
  .on("saved", function (m) {})
  .once("ready", function (m) {});

instance.off("saved"); // remove all "saved" handlers
instance.destroy(); // tear down

Embed.init(root?)

Scans root (default: document) for [data-embed] elements and mounts any not yet initialized. Returns the array of instances created. Runs automatically on DOM ready; call it manually after inserting embed markup dynamically (SPAs). It's idempotent — already-mounted elements are skipped.

Embed.init(); // scan the whole document
Embed.init(containerEl); // or just a subtree

Embed.products()

Returns the surface names accepted by render, e.g. ["template", "broadcast", "broadcastList", "chatbot", "teamChat"].

Embed.version

The loader version string, e.g. "1.0.0".

Declarative mounting

Mount with markup and zero render code. The loader scans for [data-embed] on DOM ready (and via Embed.init) and mounts each element.

<div
  data-embed="chatbot"
  data-chatbot-id="cb_123"
  data-auth-token="<jwt>"
  data-theme="system"
  style="height: 720px"
></div>

Every data-* attribute maps to an option (the browser camel-cases dataset keys):

AttributeOption
data-embedthe product (first arg to render)
data-api-keyapiKey
data-auth-tokenauthToken
data-themetheme
data-base-urlbaseUrl
data-chatbot-idchatbotId
data-agent-idagentId
data-from-broadcastfromBroadcast
data-statusesstatuses
data-redirect-urlredirectUrl
data-show-create-buttonshowCreateButton

The mounted instance is available as element._embed.

Events as DOM CustomEvents

Declaratively-mounted surfaces re-emit every event as a DOM CustomEvent named embed:<event> on the host element, with the payload in event.detail. This lets a page listen the same way for every surface:

<script>
  var el = document.querySelector('[data-embed]');
  el.addEventListener("embed:ready", function (e) {
    console.log(e.detail);
  });
  el.addEventListener("embed:published", function (e) {
    console.log(e.detail);
  });
</script>

Event names by surface

SurfaceEvents (besides ready)
chatbotsaved, published
templatecreated, cancelled
broadcastcreated, cancelled
broadcastList— (only ready)
teamChatmessageSent, messageDelivered, messageIncoming, conversationChanged

ready fires for every surface. As DOM CustomEvents these are prefixed embed: (e.g. embed:saved).

Security model

  • Pass one of apiKey / authToken; authToken wins when both are set. Prefer a short-lived authToken in browser contexts — see the auth note.
  • The loader sends your page origin to the iframe as parentOrigin. The surface only posts events back to that exact origin (never *), so payloads can't leak to another frame.
  • Inbound events are filtered by source iframe and origin before dispatch, so multiple embeds on one page stay isolated.

How is this guide?

On this page