> ## Documentation Index
> Fetch the complete documentation index at: https://docs.getaptly.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Embed App Actions

> Trigger Aptly UI interactions (open a card, start a call, compose an email, and more) from an embedded iframe app using the SDK or raw postMessage.

Embedded apps running inside Aptly can trigger UI interactions in the parent window — opening a card, starting a phone call, launching the email composer, creating an event, and more — by posting a browser message. Aptly executes the action if your app has been granted that permission.

This works alongside [delegate token authentication](/delegate-tokens). You can use one, the other, or both.

***

## Using the Aptly SDK (recommended)

If your app includes the [Aptly SDK](/aptly-sdk-reference), use the named wrapper methods. They return a `Promise<{ success: boolean, error?: string }>`, handle the response listener for you, and time out after 3 seconds.

```js theme={null}
await aptly.openCardPane({ cardId: "abc123" });
await aptly.openCardView({ cardId: "abc123" });
await aptly.startDialer({ number: "+15551234567", name: "Jane Smith" });
await aptly.openEmailComposer({
  subject: "Hello",
  content: "<p>Hi</p>",
  composeMode: "email"
});
await aptly.createEvent({
  date: "2026-06-15T10:00:00.000Z",
  comments: "Walkthrough"
});
await aptly.createCard({ boardId: "board-uuid", fields: { name: "New Lead" } });
await aptly.createTask({
  title: "Follow up",
  dueAt: "2026-06-15T09:00:00.000Z",
  priority: "high"
});
await aptly.createContact({
  firstname: "Jane",
  lastname: "Smith",
  email: "jane@example.com"
});
await aptly.navigateToContact({ contactId: "person123" });

// Generic escape hatch — useful when the action ID is dynamic
await aptly.action("start-dialer", { number: "+15551234567" });

// Check which actions are available at runtime before calling
console.log(aptly.actions); // e.g. ['start-dialer', 'create-card']
```

***

## Raw postMessage

If you are not using the SDK, post a message directly to the parent window. Aptly validates the permission and sends a response.

```js theme={null}
const APTLY_ORIGIN = "https://app.getaptly.com"; // use https://preview.getaptly.com for preview

window.parent.postMessage(
  {
    type: "aptly-action",
    action: "start-dialer",
    payload: { number: "+15551234567", name: "Jane Smith" }
  },
  APTLY_ORIGIN
);
```

Listen for the response:

```js theme={null}
const APTLY_ORIGINS = [
  "https://app.getaptly.com",
  "https://preview.getaptly.com"
];

window.addEventListener("message", (event) => {
  if (!APTLY_ORIGINS.includes(event.origin) || event.source !== window.parent)
    return;
  if (event.data?.type === "aptly-action-result") {
    const { action, success, error } = event.data;
    if (!success) console.warn(`Action ${action} failed: ${error}`);
  }
});
```

Aptly responds with `{ type: 'aptly-action-result', action, success: true }` or `{ ..., success: false, error: 'Not permitted' }`.

***

## Enabling actions for your app

Actions must be explicitly granted — nothing runs by default. An admin configures this in the settings for the specific embed.

**Marketplace app:** In Global Admin → App Marketplace, open your app's edit modal → Permissions tab → Embed Actions. When a user installs the app on a board, these permissions are copied to that board tab and can be adjusted in board settings.

**Custom board tab:** In Board Settings → your tab → edit → Allowed Actions.

**Dashboard widget:** In Dashboard → add or edit app → Embed Actions.

***

## Available actions

### `open-card-pane`

Navigates to a specific card in the board's side panel.

```js theme={null}
await aptly.openCardPane({ cardId: "abc123" });
```

| Field    | Type   | Required | Description                    |
| -------- | ------ | -------- | ------------------------------ |
| `cardId` | string | Yes      | The `_id` of the card to open. |

***

### `open-card-view`

Opens a card in a fullscreen detail view (floating modal).

```js theme={null}
await aptly.openCardView({ cardId: "abc123" });
```

| Field    | Type   | Required | Description                    |
| -------- | ------ | -------- | ------------------------------ |
| `cardId` | string | Yes      | The `_id` of the card to open. |

***

### `start-dialer`

Opens the Aptly phone dialer with a number pre-filled.

```js theme={null}
await aptly.startDialer({ number: "+15551234567", name: "Jane Smith" });
```

| Field    | Type   | Required | Description                                    |
| -------- | ------ | -------- | ---------------------------------------------- |
| `number` | string | Yes      | Phone number in E.164 format (`+15551234567`). |
| `name`   | string | No       | Contact name to display in the dialer.         |

***

### `open-email-composer`

Opens a new email compose window, optionally pre-filled.

```js theme={null}
await aptly.openEmailComposer({
  to: [{ value: "jane@example.com", label: "Jane Smith" }],
  subject: "Follow-up on your application",
  content: "<p>Hi there,</p><p>Just following up...</p>",
  composeMode: "email"
});
```

| Field         | Type                                        | Required | Description                                                                                                                                                                                    |
| ------------- | ------------------------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `to`          | string \| string\[] \| `{ value, label }[]` | No       | Pre-filled recipients — a single address, an array of addresses, or an array of `{ value, label }` objects. Email addresses when `composeMode` is `'email'`, phone numbers when it is `'sms'`. |
| `subject`     | string                                      | No       | Pre-filled subject line.                                                                                                                                                                       |
| `content`     | string                                      | No       | Pre-filled body content (HTML supported).                                                                                                                                                      |
| `composeMode` | `'email'` \| `'sms'`                        | No       | Defaults to `'email'`.                                                                                                                                                                         |

***

### `create-event`

Opens the calendar event editor, optionally pre-filled.

```js theme={null}
await aptly.createEvent({
  date: "2026-06-15T10:00:00.000Z",
  comments: "Property walkthrough",
  recipients: [{ email: "tenant@example.com", name: "Alex Tenant" }]
});
```

| Field        | Type            | Required | Description                                                                     |
| ------------ | --------------- | -------- | ------------------------------------------------------------------------------- |
| `date`       | ISO 8601 string | No       | Pre-filled event start date/time.                                               |
| `comments`   | string          | No       | Pre-filled event description.                                                   |
| `recipients` | array           | No       | Pre-filled attendees. Each object should include `email` and optionally `name`. |

***

### `create-card`

Opens the new card form on a specific board, optionally pre-filled.

```js theme={null}
await aptly.createCard({
  boardId: "board-uuid-here",
  fields: {
    name: "New Applicant",
    email: "applicant@example.com"
  }
});
```

| Field     | Type   | Required | Description                                                                                  |
| --------- | ------ | -------- | -------------------------------------------------------------------------------------------- |
| `boardId` | string | Yes      | UUID of the board to create the card on.                                                     |
| `fields`  | object | No       | Key-value pairs of field values to pre-fill. Keys are field UUIDs or well-known field names. |

***

### `create-task`

Opens the task creation form, optionally pre-filled. Common use case: a "remind me later" button that pre-fills a future due date.

```js theme={null}
await aptly.createTask({
  title: "Follow up with tenant",
  dueAt: "2026-06-15T09:00:00.000Z",
  priority: "high",
  note: "Check in about lease renewal"
});
```

| Field              | Type                                          | Required | Description                        |
| ------------------ | --------------------------------------------- | -------- | ---------------------------------- |
| `title`            | string                                        | No       | Pre-filled task title.             |
| `dueAt`            | ISO 8601 string                               | No       | Pre-filled due date/time.          |
| `activityLogType`  | `'todo'` \| `'email'` \| `'sms'` \| `'voice'` | No       | Task type. Defaults to `'todo'`.   |
| `priority`         | `'asap'` \| `'high'` \| `'medium'` \| `'low'` | No       | Pre-filled priority.               |
| `note`             | string                                        | No       | Pre-filled task description.       |
| `assigneeId`       | string                                        | No       | User ID to pre-assign the task to. |
| `aptletInstanceId` | string                                        | No       | Card `_id` to link the task to.    |
| `aptletUuid`       | string                                        | No       | Board UUID for context.            |

***

### `create-contact`

Opens the contact creation modal, optionally pre-filled.

```js theme={null}
await aptly.createContact({
  firstname: "Jane",
  lastname: "Smith",
  phone: "+14155551234",
  email: "jane@example.com"
});
```

| Field       | Type   | Required | Description               |
| ----------- | ------ | -------- | ------------------------- |
| `firstname` | string | No       | Pre-filled first name.    |
| `lastname`  | string | No       | Pre-filled last name.     |
| `phone`     | string | No       | Pre-filled phone number.  |
| `email`     | string | No       | Pre-filled email address. |
| `company`   | string | No       | Pre-filled company name.  |
| `title`     | string | No       | Pre-filled job title.     |

***

### `navigate-to-contact`

Navigates to a contact's record page.

```js theme={null}
await aptly.navigateToContact({ contactId: "person123" });
```

| Field       | Type   | Required | Description                                    |
| ----------- | ------ | -------- | ---------------------------------------------- |
| `contactId` | string | Yes      | The `_id` of the person record to navigate to. |

***

## Troubleshooting

**Action fires but nothing happens.** Check that the action is listed under Allowed Actions for the specific embed where your app is running. Permission is configured per embed, not globally.

**Response says `success: false, error: 'Not permitted'`.** The action is not in the embed's allowed list. An admin needs to enable it in the app or board settings.

**No response message at all.** Ensure your app is loaded inside an Aptly embed (not a standalone tab) and that the message is sent via `window.parent`. The SDK wrappers handle this correctly.

**`open-email-composer` opens but the To field is empty.** Pre-filling recipients is not yet supported for this action — the user can type recipients manually after the composer opens.
