> For the complete documentation index, see [llms.txt](https://apizee.gitbook.io/apizee-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://apizee.gitbook.io/apizee-docs/embed/api-reference/postmessage-api-reference.md).

# IFrame integration

Get data and control Embed video call component through the postMessage protocol.

The agent-side interface is accessible at `https://app.apizee.com/agent/`. It is a web application that can be configured via URL parameters and controlled at runtime via the PostMessage API.

## URL parameters

### Required parameters

<table><thead><tr><th width="135">Parameter</th><th width="182">Stands for</th><th>Description</th></tr></thead><tbody><tr><td><code>iK</code><mark style="color:red;">*</mark></td><td><code>identificationKey</code></td><td>Identification key of your company.</td></tr><tr><td><code>cN</code><mark style="color:red;">*</mark></td><td><code>conversationName</code></td><td>ApiRTC conversation name.<br><em>Not required if set at runtime using the</em> <em><code>application.conversation.set</code></em> <em>PostMessage</em></td></tr></tbody></table>

{% hint style="info" %}
The identification key is provided by your customer success manager after registering to our services.

Please contact our sales team at <contact@apizee.com>.
{% endhint %}

### Optional parameters

<table><thead><tr><th width="116">Parameter</th><th width="181">Stands for</th><th width="148">Default</th><th>Description</th></tr></thead><tbody><tr><td><code>iI</code></td><td><code>installationId</code></td><td><code>APZ_AGENT_</code></td><td>Used as a prefix for local storage keys. Useful to differentiate between platforms (e.g. Zendesk, Salesforce).</td></tr><tr><td><code>l</code></td><td><code>lang</code></td><td>Browser config</td><td>Force the UI language. Must be an <a href="https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes">ISO 639-1</a> code (e.g. <code>en</code>, <code>fr</code>).</td></tr><tr><td><code>lL</code></td><td><code>logLevel</code></td><td><code>warn</code></td><td>Log verbosity level (<code>debug</code>, <code>info</code>, <code>warn</code>, <code>error</code>).</td></tr><tr><td><code>eR</code></td><td><code>externalReferences</code></td><td><em>(empty)</em></td><td>External references attached to the interaction (e.g. CRM case IDs). Expected format, URL-encoded: <code>encodeURIComponent(JSON.stringify([{ "name": "ticketId", "reference": "12345" }]))</code></td></tr><tr><td><code>c</code></td><td><code>contacts</code></td><td><em>(empty)</em></td><td>Pre-filled contact list as a URL-encoded JSON array: <code>encodeURIComponent(JSON.stringify([{"name":"…","phone":"…","email":"…"}]))</code>. All fields are optional.</td></tr></tbody></table>

#### Deprecated parameters

Deprecated URL parameters keep working for **at least 6 months** after their deprecation is announced, giving you time to migrate.

| Parameter | Stands for   | Migration                               |
| --------- | ------------ | --------------------------------------- |
| `aK`      | `apiKey`     | Use `iK` (`identificationKey`) instead. |
| `gP`      | `guestPhone` | Use `c` (`contacts`) instead.           |
| `gN`      | `guestName`  | Use `c` (`contacts`) instead.           |

## PostMessage API

The agent-side application supports 2-way communication with the host platform via the standard [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) API:

* **From the agent app to the host platform** — the app notifies the host of events (invitation link generated, message sent, transcription received, etc.)
* **From the host platform to the agent app** — the host can push configuration and update session data at runtime

#### Event lifecycle

Each event emitted by the agent app carries a `status` field:

<table data-full-width="false"><thead><tr><th width="161">Status</th><th>Meaning</th></tr></thead><tbody><tr><td><code>stable</code></td><td>Production-ready. Payload structure will not change without a deprecation notice.</td></tr><tr><td><code>experimental</code></td><td>Subject to change without notice. Do not rely on it in production.</td></tr><tr><td><code>deprecated</code></td><td>Still functional but scheduled for removal. Migrate to the replacement event.</td></tr></tbody></table>

**Breaking change policy:** a `stable` event is never modified in a breaking way. Any structural change to a `stable` event produces a **new event key**. The old one is then marked `deprecated` with a `removeAt` date and a migration path. Once deprecated, an event keeps being emitted for **at least 6 months** before its `removeAt` date.

#### Event envelope

All current events emitted by the agent app follow this envelope:

```json
{
  "key": "event.name",
  "status": "stable",
  "sentAt": "2026-01-01T10:00:00.000Z",
  "success": true,
  "payload": { }
}
```

On failure:

```json
{
  "key": "event.name",
  "status": "stable",
  "sentAt": "2026-01-01T10:00:00.000Z",
  "success": false,
  "error": {
    "code": "UNKNOWN",
    "message": "Optional human-readable description"
  },
  "payload": { }
}
```

When an event is deprecated, a `deprecation` field is added:

```json
{
  "key": "event.name",
  "status": "deprecated",
  "sentAt": "2026-01-01T10:00:00.000Z",
  "deprecation": {
    "since": "2025-12-01",
    "removeAt": "2026-12-01",
    "replacement": {
      "key": "new.event.name",
      "message": "Optional migration guidance"
    },
    "docsUrl": "https://..."
  },
  "success": true,
  "payload": { }
}
```

### From the agent-side app to the host platform

Register a listener on the host side to receive events:

```js
const AGENT_APP_DOMAIN = 'https://app.apizee.com';

window.addEventListener('message', (event) => {
  if (event.origin !== AGENT_APP_DOMAIN) return;
  const { key, success, payload, error } = event.data;
  // handle event
});
```

***

#### `application.listener.initialized`

**Status:** `stable`

Emitted once when the agent app has finished loading and is ready to receive messages from the host. This is the signal to start sending configuration via PostMessage.

**Payload**

```json
{
  "key": "application.listener.initialized",
  "status": "stable",
  "sentAt": "2026-01-01T10:00:00.000Z",
  "success": true,
  "payload": {
    "canReceive": ["configuration", "conversation", "guest_data", "lang"],
    "canSend": [
      "application.listener.initialized",
      "invitation.link.created",
      "invitation.message.sent",
      ...
    ]
  }
}
```

| Field                | Type       | Description                                   |
| -------------------- | ---------- | --------------------------------------------- |
| `payload.canReceive` | `string[]` | List of input message types the app accepts   |
| `payload.canSend`    | `string[]` | List of output message types the app may emit |

***

#### `invitation.link.created`

**Status:** `stable`

Emitted when an invitation link has been successfully generated for a guest. Fired once per invited recipient.

**Success payload**

```json
{
	"key": "invitation.link.created",
	"status": "stable",
	"sentAt": "2026-04-22T10:00:00.000Z",
	"success": true,
	"payload": {
		"recipient": {
			"value": "john@example.com",
			"type": "mail",
			"name": "John",
			"order": 1
		},
		"invitationLink": "https://guest.example.com/inv123"
	}
}
```

**Failure payload**

```json
{
	"key": "invitation.link.created",
	"status": "stable",
	"sentAt": "2026-04-22T10:00:00.000Z",
	"success": false,
	"error": {
		"code": "UNKNOWN",
		"message": "An unknown error occurred while creating the invitation link."
	},
	"payload": {
		"recipient": {
			"value": "john@example.com",
			"type": "mail",
			"name": "John",
			"order": 1
		}
	}
}
```

| Field                     | Type                  | Description                                                         |
| ------------------------- | --------------------- | ------------------------------------------------------------------- |
| `payload.recipient.value` | `string`              | Email address or phone number of the invited guest                  |
| `payload.recipient.type`  | `"mail" \| "phone"`   | Type of the recipient identifier                                    |
| `payload.recipient.name`  | `string \| undefined` | Display name of the guest, if available                             |
| `payload.recipient.order` | `number`              | Invitation sequence (1 for the first guest, 2 for the second, etc.) |
| `payload.invitationLink`  | `string`              | *(success only)* The generated invitation URL                       |
| `error.code`              | `string`              | *(failure only)* Standardized error code (e.g. `"UNKNOWN"`)         |
| `error.message`           | `string \| undefined` | *(failure only)* Optional error details                             |

***

#### `invitation.message.sent`

**Status:** `stable`

Emitted after the invitation message (SMS or email) has been dispatched to the guest. Fired once per invited recipient.

**Success payload**

```json
{
  "key": "invitation.message.sent",
  "status": "stable",
  "sentAt": "2026-04-22T10:00:00.000Z",
  "success": true,
  "payload": {
    "recipient": {
			"value": "+33612345678",
			"type": "phone",
			"name": "John",
			"order": 1
		},
    "invitationLink": "https://guest.example.com/inv123"
  }
}
```

**Failure payload**

```json
{
  "key": "invitation.message.sent",
  "status": "stable",
  "sentAt": "2026-04-22T10:00:00.000Z",
  "success": false,
  "error": {
    "code": "SMS_FAILED",
    "message": "An unknown error occurred while sending the invitation."
  },
  "payload": {
    "recipient": {
			"value": "+33612345678",
			"type": "phone",
			"name": "John",
			"order": 1
		},
    "invitationLink": "https://guest.example.com/inv123"
  }
}
```

| Field                     | Type                  | Description                                                                 |
| ------------------------- | --------------------- | --------------------------------------------------------------------------- |
| `payload.recipient.value` | `string`              | Email address or phone number of the invited guest                          |
| `payload.recipient.type`  | `"mail" \| "phone"`   | Type of the recipient identifier                                            |
| `payload.recipient.name`  | `string \| undefined` | Display name of the guest, if available                                     |
| `payload.recipient.order` | `number`              | Invitation sequence (1 for first guest, 2 for second, etc.)                 |
| `payload.invitationLink`  | `string`              | The invitation URL that was sent                                            |
| `error.code`              | `string`              | *(failure only)* Standardized error code (e.g. `"UNKNOWN"`, `"SMS_FAILED"`) |
| `error.message`           | `string \| undefined` | *(failure only)* Optional error details                                     |

***

#### `visio.transcription.received`

**Status:** `stable`

Emitted each time a new transcription entry is received during the session.

**Payload**

```json
{
	"key": "visio.transcription.received",
	"status": "stable",
	"sentAt": "2026-04-22T10:00:00.000Z",
	"success": true,
	"payload": {
		"contact": {
			"name": "Agent Name"
		},
		"content": "Hello, how can I help you today?"
	}
}
```

| Field                  | Type     | Description                                     |
| ---------------------- | -------- | ----------------------------------------------- |
| `payload.contact.name` | `string` | Name of the speaker (agent or guest identifier) |
| `payload.content`      | `string` | Transcribed text of the message                 |

#### ​`visio.snapshot.taken`

**Status:** `stable`

Emitted when the agent takes a video snapshot. Replaces the legacy `snapshot` event.

**Success payload**

```json
{
	"key": "visio.snapshot.taken",
	"status": "stable",
	"sentAt": "2026-04-22T10:00:00.000Z",
	"success": true,
	"payload": {
		"snapshotUrl": "data:image/png;base64,..."
	}
}
```

**Failure payload**

```json
{
	"key": "visio.snapshot.taken",
	"status": "stable",
	"sentAt": "2026-04-22T10:00:00.000Z",
	"success": false,
	"error": {
		"code": "SNAPSHOT_FAILED",
		"message": "An error occurred while taking the snapshot."
	}
}
```

| Field                 | Type                  | Description                                            |
| --------------------- | --------------------- | ------------------------------------------------------ |
| `payload.snapshotUrl` | `string`              | *(success only)* Base64-encoded PNG image URL          |
| `error.code`          | `string`              | *(failure only)* Error code (e.g. `"SNAPSHOT_FAILED"`) |
| `error.message`       | `string \| undefined` | *(failure only)* Optional error details                |

***

#### `visio.subscribed_streams.updated`

**Status:** `stable`

Emitted whenever the number of subscribed remote video streams changes. Replaces the legacy `subscribed_streams` event.

**Payload**

```json
{
	"key": "visio.subscribed_streams.updated",
	"status": "stable",
	"sentAt": "2026-04-22T10:00:00.000Z",
	"success": true,
	"payload": {
		"length": 2
	}
}
```

| Field            | Type     | Description                                 |
| ---------------- | -------- | ------------------------------------------- |
| `payload.length` | `number` | Current number of active subscribed streams |

***

#### Deprecated output events

**`ready`**

> **Deprecated** since `2026-04-29` — will be removed on `2027-04-29`.\
> **Migration:** use `application.listener.initialized` instead.

```json
{ "type": "ready" }
```

**`sms_sent`**

> **Deprecated** since `2026-03-18` — will be removed on `2027-04-29`.\
> **Migration:** use `invitation.message.sent` instead.

```json
{
  "type": "sms_sent",
  "name": "John",
  "phone": "+33612345678",
  "link": "https://guest.example.com/inv123",
  "contact": { "sortOrder": 1 }
}
```

**`sms_fail`**

> **Deprecated** since `2026-03-18` — will be removed on `2027-04-29`.\
> **Migration:** use `invitation.message.sent` (with `success: false`) instead.

```json
{
	"type": "snapshot",
	"dataUrl": "data:image/png;base64,...",
	"contact": {
		"id": "contact-id",
		"conversationName": "conversation-name",
		"userData": {}
	}
}
```

**`subscribed_streams`**

> **Deprecated** since `2026-04-29` — will be removed on `2027-04-29`.\
> **Migration:** use `visio.subscribed_streams.updated` instead.

```json
{
	"type": "subscribed_streams",
	"length": 2
}
```

***

### From the host platform to the agent-side app <a href="#from-the-host-platform-to-the-agent-side-app" id="from-the-host-platform-to-the-agent-side-app"></a>

The host application can control the agent app by posting messages to the iframe element:

```js
const AGENT_APP_DOMAIN = 'https://app.apizee.com';
const iframe = document.getElementById('visio-iframe');

iframe.contentWindow.postMessage(
	{
		key: 'application.configuration.set',
		payload: {
			conversationName: 'my-session-001',
		},
	},
	AGENT_APP_DOMAIN
);
```

> **Important:** wait for `application.listener.initialized` before sending any message, to ensure the app is ready to process it.

New input messages use the same envelope format as output events, with a `key` field and a `payload` object. Legacy messages continue to use a flat object with a `type` field.

***

#### `application.configuration.set`

**Status:** `stable`

Sends the full application configuration to the agent app. Takes precedence over URL parameters for any overlapping field.

> This is the replacement for the deprecated `configuration` message.

```json
{
	"key": "application.configuration.set",
	"payload": {
		"conversationName": "my-session-001",
		"logLevel": "debug"
	}
}
```

| Field                        | Type                  | Description                                                                                                                   |
| ---------------------------- | --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `payload.conversationName`   | `string \| undefined` | Name of the conversation session                                                                                              |
| `payload.installationId`     | `string \| undefined` | Installation identifier (used as local storage key prefix)                                                                    |
| `payload.logLevel`           | `string \| undefined` | Log verbosity level (`"debug"`, `"info"`, `"warn"`, `"error"`)                                                                |
| `payload.externalReferences` | `string \| undefined` | External references attached to the interaction. Expected format: `encodeURIComponent(JSON.stringify([{ name, reference }]))` |

***

#### `application.conversation.set`

**Status:** `stable`

Updates the conversation name used by the agent app for the current session.

> This is the replacement for the deprecated `conversation` message.

```json
{
	"key": "application.conversation.set",
	"payload": {
		"conversationName": "my-session-001"
	}
}
```

| Field                      | Type     | Description           |
| -------------------------- | -------- | --------------------- |
| `key`                      | `string` | Event identifier      |
| `payload.conversationName` | `string` | New conversation name |

***

#### `guest_data`

**Status:** `stable`

Updates the guest's pre-filled information (name and phone number).

```json
{
	"type": "guest_data",
	"data": {
		"name": "John Doe",
		"phone": "+33612345678"
	}
}
```

| Field        | Type                  | Description        |
| ------------ | --------------------- | ------------------ |
| `type`       | `"guest_data"`        | Event identifier   |
| `data.name`  | `string \| undefined` | Guest display name |
| `data.phone` | `string \| undefined` | Guest phone number |

***

#### Deprecated input events

**`configuration`**

> **Deprecated** since `2026-04-29` — will be removed on `2027-04-29`.\
> **Migration:** use `application.configuration.set` instead.

```json
{
	"type": "configuration",
	"data": {
		"conversationName": "my-session-001",
		"logLevel": "debug"
	}
}
```

**`conversation`**

> **Deprecated** since `2026-04-29` — will be removed on `2027-04-29`.\
> **Migration:** use `application.conversation.set` instead.

```json
{
	"type": "conversation",
	"name": "my-session-001"
}
```

**`lang`**

> **Deprecated** since `2026-04-08` — will be removed on `2027-04-08`.\
> **Migration:** use the URL parameter `?l=en` to set the application language instead.

```json
{
	"type": "lang",
	"lang": "en"
}
```

***

### Full integration example

#### Listening (host platform)

```js
const AGENT_APP_DOMAIN = 'https://app.apizee.com';

window.addEventListener('message', (event) => {
	if (event.origin !== AGENT_APP_DOMAIN) return;

	const message = event.data;

	// New event format (key-based)
	if (message.key) {
		if (message.status === 'deprecated' && message.deprecation) {
			console.warn(
				`[Visio] Event "${message.key}" is deprecated since ${message.deprecation.since}.`,
				`Replacement event: ${message.deprecation.replacement?.key}`
			);
		}

		switch (message.key) {
			case 'application.listener.initialized':
				console.log('Visio app is ready', message.payload);
				break;

			case 'invitation.link.created':
				if (message.success) {
					console.log('Invitation link created:', message.payload.invitationLink);
				} else {
					console.error('Invitation link creation failed:', message.error);
				}
				break;

			case 'invitation.message.sent':
				if (message.success) {
					console.log('Invitation sent to:', message.payload.recipient);
				} else {
					console.error('Invitation sending failed:', message.error);
				}
				break;

			case 'visio.transcription.received':
				console.log(`[${message.payload.contact.name}]: ${message.payload.content}`);
				break;
				
			case 'visio.snapshot.taken':
				if (message.success) {
					console.log('Snapshot data:', message.payload.snapshotUrl);
				} else {
					console.error('Failed to take snapshot:', message.error);
				}
				break;
				
			case 'visio.subscribed_streams.updated':
				console.log(`Number of subscribed sctreams updated: ${message.payload.length}`);
				break;
		}
		return;
	}
});
```

#### Sending (host platform)

```js
const AGENT_APP_DOMAIN = 'https://app.apizee.com';
const iframe = document.getElementById('visio-iframe');

// Wait for the app to be ready before sending messages
window.addEventListener('message', (event) => {
	if (event.origin !== AGENT_APP_DOMAIN) return;

	if (event.data?.key === 'application.listener.initialized') {
		iframe.contentWindow.postMessage(
			{
				key: 'application.configuration.set',
				payload: {
					conversationName: 'session-42',
				},
			},
			AGENT_APP_DOMAIN
		);
	}
});
```
