Skip to Content

Messaging

AppLink uses the browser’s PostMessage API to communicate between your app (in an iframe) and the Finqu Commerce host. This page describes how messages are structured, how to subscribe to them, and how to send messages to the host.

Message flow

The host and your app exchange structured messages. The host sends an Initialize message first; after that, both sides can send and receive messages. Only messages that pass origin validation (when you set an origin other than '*') are delivered.

IMessage shape

Every message conforms to the IMessage interface. You will see this in subscribe callbacks and use it when dispatching.

FieldTypeDescription
componentobjectIdentifies the component: id, type, group (e.g. ComponentGroup.Dialog).
actionstringAction name (e.g. Show, Confirm, Close, Create, Save).
keystringInternal key finqu::app-link::{type}::{action}.
idstringUnique message id.
refIdstring | nullId of the message this one refers to (e.g. for callbacks).
payloadobjectAction-specific data.
callbackbooleanWhether the sender expects a callback.
clientIdstring | nullSet by AppLink when your app dispatches.
sessionIdstring | nullSet by AppLink when your app dispatches.

When you call app.dispatch(message), AppLink fills in clientId, sessionId, and normalizes payload to an object if missing.

Example message (in a subscribe callback):

{ component: { id: '...', type: 'Dialog', group: 'Dialog' }, action: 'Show', key: 'finqu::app-link::Dialog::Show', id: '...', refId: null, payload: { title: 'Confirm', content: '...', buttons: { ... } }, callback: true, clientId: '...', sessionId: '...' }

Subscribing to messages

You can subscribe to every message or only to messages for a given component group.

Subscribe to all messages

Pass a single callback. Your callback runs for every message (except the internal Initialize).

import { App } from '@finqu/app-link'; const app = App.create('my-app-id', 'https://admin.example.com'); app.ready(() => { app.subscribe((message) => { console.log(message.component.group, message.action, message.payload); }); });

Subscribe by component group

Pass a ComponentGroup and then the callback. Only messages whose message.component.group matches that group are passed to the callback.

import { App, ComponentGroup } from '@finqu/app-link'; app.subscribe(ComponentGroup.Dialog, (message) => { if (message.action === 'Confirm') { // User confirmed the dialog } if (message.action === 'Close') { // Dialog was closed } }); app.subscribe(ComponentGroup.Resource, (message) => { if (message.action === 'Create') { const resourceType = message.payload?.type; const resourceId = message.payload?.id; // Load resource and show UI } });

This keeps your handlers focused and avoids a single large switch on component.group.

Unsubscribing

subscribe() returns a function. Call it to remove the subscription.

const unsubscribe = app.subscribe(ComponentGroup.Dialog, handler); // When you no longer need it (e.g. component unmount): unsubscribe();

You can also call app.unsubscribe(handler) with the same callback reference.

Dispatching messages to the host

Use app.dispatch(message) to send a message to the host. AppLink sets message.clientId and message.sessionId and ensures message.payload is an object. You must supply at least component, action, and usually payload.

Most host features (dialogs, resources, navigation) are driven by the host: the host creates components and sends messages to your app; your app reacts in subscribe callbacks. When the host expects a response (e.g. a dialog callback), it sends a message with callback: true and your app may dispatch a follow-up message (e.g. ComponentCallback) that references the original message’s id via refId. The exact format is defined by the host and the component types.

Example: dispatching a message (conceptual)

If you were to build an IMessage by hand (e.g. for a custom integration), it would look like this:

import { App, ComponentGroup, IMessage } from '@finqu/app-link'; const message: IMessage = { id: '...', // uuid key: 'finqu::app-link::SomeType::SomeAction', component: { id: 'component-id', type: 'SomeType', group: ComponentGroup.Dialog }, action: 'SomeAction', payload: { ... }, refId: null, callback: false, clientId: null, sessionId: null }; app.dispatch(message);

In practice, the host creates components and sends you messages; you rarely construct full IMessage objects yourself unless you are implementing a custom protocol. Your main use of dispatch from the app is often to send callbacks (e.g. after the user confirms a dialog) in the format the host expects.

Example: responding to a dialog with a callback

When the host shows a dialog and sets callback: true, it may expect your app to dispatch a callback message when the user confirms. The host’s message will have an id; the callback message typically references it with refId and uses the component action that the host documents (e.g. ComponentCallback). The exact payload and action names depend on the host implementation. Conceptually:

  1. Host sends a message (e.g. Dialog / Show) with callback: true and a message id.
  2. Your app subscribes to ComponentGroup.Dialog and receives the message.
  3. When the user confirms, your app dispatches a message that has refId: originalMessage.id and the appropriate action and payload so the host can close the dialog and continue.

Implement the exact action names and payloads according to the Finqu Commerce host documentation or the component types (Dialog, Confirm, etc.) used by the host.

Next: Component groups and resources for the list of component groups, resource types, and typical patterns.