Header Image
NAV Navbar

Introduction

Mainframe is a new decentralized messaging protocol focused on privacy, productivity, & extensibility.

We’ve built the first application that leverages this protocol and we’re opening up the alpha version of the platform so that developers can start building rich, interactive experiences inside.

This documentation will guide you through the process of creating a simple Mainframe bot that you’ll be able to use immediately in all Mainframe clients.

Getting started

Registration

Open the More Settings screen in the main menu

Go to the bottom of the settings screen

Go to the bottom of the  screen

The first thing you will need is to register your bot with Mainframe, by opening the developer portal in the Mainframe client and creating a new bot.

  1. Open the main menu by clicking your avatar/name and press the MORE SETTINGS button to open the settings.

  2. At the bottom of the settings screen, find the DEVELOPER section and press the MY BOTS button.

  3. Go to the bottom of the screen and press the NEW BOT button.

  4. Fill the bot creation form.

The username will be an unique identifier for your bot in Mainframe, if it is already used by a Mainframe user or another bot, the registration will fail and you will have to choose another username.
The username can only contain lowercase alphanumeric characters and underscores.

You will need to fill the entire BASIC section of the form and provide your bot WebHook URL in the the CONFIG section.

Once you have completed the form, press the SAVE button and and copy the provided secret. Keep this secret safe, you will need it when communicating with the Mainframe API.

Hello world

// Import the server factory from the bot SDK
const { startServer } = require('@mainframe/bot-sdk')

// Start the server with the provided handlers
startServer({
  // Add handler for bot being added to a conversation
  conversation_added(payload, context) {
    // Send a "Hello world" message to the conversation the bot has been added to
    context.sendMessage({
      conversation_id: payload.conversation_id,
      message: 'Hello world',
    })
  },
})
Event from Mainframe: your bot got added to a conversation

POST https://bot-api.example.com/conversation_added HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "user_id": "<unique user ID>",
  "conversation_id": "<unique conversation ID>"
}

Let's get started by building a bot that simply sends a "Hello world" message when added to a conversation.

To achieve this, your bot server will need to implement the /conversation_added endpoint.

Once your bot is added to a conversation, the Mainframe server will call your service's /conversation_added endpoint with the payload presented on the side.

Message from your bot

POST https://api.mainframe.com/bots/v1/send_message HTTP/1.1
Authorization: Mainframe-Bot <your bot secret>
Content-Type: application/json; charset=utf-8

{
  "conversation_id": "<conversation ID provided by Mainframe>",
  "message": "Hello world"
}

You can ignore the user_id for now, but we will need the conversation_id value to send a message by sending a POST request to https://api.mainframe.com/bots/v1/send_message, as presented on the side.

That's it! Your bot will now send a "Hello world" message any time it is added to a conversation.

Users

All users interacting with your bot will be registered Mainframe users using one of the clients. As such, you can consider they are authenticated with Mainframe and uniquely identified by the user_id provided.

Authentication

If your service provides its own authentication and user data, you may want to associate Mainframe users with your own users.

To achieve this, any /post request can return a response containing an AuthenticationData payload the client will use to open the provided URL.
Once the authentication is complete, or if it fails or gets cancelled by the user, your server must bring the user back to the Mainframe client, either by using a specific web page on our domain, or open the Mainframe app directly by providing one of the following states:

  • cancel when the user cancels the authentication flow
  • error when an error occurs, preventing the user from authenticating
  • success when the user is successfully authenticated

If your authentication does not have a dedicated page to redirect the user, you can use the one provided by Mainframe: https://mainframe.com/bots/auth/?state={state}&name={name}&logo_url={url}, with the following values:

  • state: one of "cancel", "error" or "success", see above
  • name: the name of your bot (optional)
  • logo_url: URL of your logo (optional)

You can also decide to redirect directly to the Mainframe app, using the mainframe://bots/authentication/{state} URI, where state has a value of "cancel", "error" or "success" as presented above.

If you provide a payload Object as part of the AuthenticationData, the client will perform a /post request to your bot server with this payload when the authentication is successful. When no payload is provided, no further action will be performed by the client once the user is back.

By default, a generic message will be displayed in the client asking the user to authenticate. You can also provide a custom message using the message field of the BotResponse.

Conversations

Conversations are a core concept of Mainframe, they are the main context where users interact with other users and bots. When the user will initiate interactions with your bot in the context of a conversation, Mainframe will provide the unique conversation_id identifying this context.

Subscriptions

// Request from the Mainframe client

POST https://bot-api.example.com/post HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "data": {
    "any": "data from subscriptionCreatePayload"
  },
  "context": {
    "user_id": "<unique user ID>",
    "conversation_id": "<unique conversation ID>",
    "subscription_token": "<unique token to use>"
  }
}
// Call to Mainframe API to setup the subscription

POST https://api.mainframe.com/bots/v1/setup_subscription HTTP/1.1
Content-Type: application/json; charset=utf-8
Authorization: Mainframe-Bot <secret>

{
  "subscription_token": "<provided token>",
  "label": "Alice's news feed"
}
// Response from Mainframe API

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "subscription_id": "<unique subscription ID>"
}
// Response from the bot server to the Mainframe client

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true
}

Subscriptions allow bot users to define specific parameters about the bot behavior for a given conversation. This can notably be used by the bot to define what kind of messages it should sent, or when.
A more advanced use case is also to allow a bot to leverage one user authentication in order to provide data from a remote server to a conversation, for example Alice could enable a "RSS bot" in a conversation and provide a RSS feed URL she has access to using her credentials, so that the RSS bot could read from the feed and send messages to the conversation associated with this subscription.

In order to enable subscriptions the bot configuration must provide a subscriptionCreatePayload Object when registering a bot. This payload must be a valid JSON Object, and will be sent by the client by calling the /post endpoint when an user decides to setup a subscription in a conversation.
If no further action is required, the bot server can return a BotResponse simply containing a {"success": true} payload, or it can initiate a client-side flow by providing a response containing an AuthenticationData or ModalData payload. When making these /post requests, the client will provide a subscription.token to the bot server in the request context. The bot server needs to make a /setup_subscription request to Mainframe's server in order to create the subscription with an human-readable label and retrieve the unique subscription_id generated.

Bots can also allow users to edit an existing subscription by providing a subscriptionEditPayload in the bot configuration and making an /edit_subscription request to Mainframe's server.

When providing a subscriptionCreatePayload in the configuration, the bot server must also ensure to implement the /delete_subscription endpoint that will be called by Mainframe when a subscription should be removed. The bot server must ensure all subscription data is cleared for the provided subscription_id when this endpoint is called. Furthermore, if somethings occurs in the bot domain to render a subscription invalid (for example, the resource subscribed to no longer exists), the bot server can inform Mainframe and have the subscription removed by making a /delete_subscription request.

Receiving messages

Messages can be received by your bot in two cases:

  • When someone explicitly mentions your bot in a conversation it is added to, ex Hello @testbot.
  • When an user having enabled your bot sends a message in the dedicated "bot" conversation. This conversation is automatically created by the Mainframe server when an user enables your bot, and will only have the user and your bot as participants.

In both cases, you can receive the messages sent by the user by implementing the /mention endpoint that will notably provide you the conversation_id you can then use to call the /send_message API to reply in the relevant conversation.

You bot can register domains for URLs it supports in order to provide rich link previews attached to the messages the links are added to.

In order to add link previews support, you need to register the relevant domains in your bot configuration, and implement the /preview endpoint.

Custom interactions

The Mainframe platform provides a lot of flexibility for bot developers to create the interactions they need with the Mainframe client and users, by providing three main UI contexts in the client:

The Mainframe platform also provides a generic handler for the bot server to receive data from the Mainframe client by implementing the /post endpoint.

Menu buttons screenshot

Menus present a simple list of buttons your bot integration can leverage to allow the user to initiate specific flows. Some flows can be very simple, for example having a menu button with type "open_url" pointing to your website or a specific page, but it is also possible to initiate interactions within the Mainframe client, using the "open_modal" type and an associated payload that will be sent to the /post endpoint of your bot server, that can in return describe an UI to display in the modal.

Messages

Message buttons screenshot

Messages are the primary asynchronous interaction between bots and users. They can be sent by the bots to any conversation they are added to, and will be visible by all users in this conversation.
Messages can contain a simple text, a complex UI, or both. By using message buttons, they can notably allow the user to interact with the bot in the context of this message.

Modals

Modal buttons screenshot

Modals provide the richest user experience a bot can implement in the Mainframe client.

While some modals can be simple "alerts" only containing a message, and eventually some buttons, they can also be used to render a component tree, and notably use the Form component to ask for user input.

Message Embeds

Embed Gif from Giphy Bot

The message embed action allows a bot to respond with Embed Data containing a UIPayload that can be inserted into a message as an attachment. For example, Giphy bot can allow the user to select a Gif to embed and respond with the appropriate embed payload.

This action can only be used inside the context of a conversation.

/post endpoint

An example request initiated by an user from a menu button

POST https://bot-api.example.com/post HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "data": {
    "action": "new_post_form"
  },
  "context": {
    "user_id": "<unique user ID>",
    "conversation_id": "<unique conversation ID>"
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true,
  "data": {
    "type": "modal",
    "ui": {
      "buttons": [
        {
          "type": "close_modal",
          "title": "Cancel"
        },
        {
          "type": "form_post",
          "title": "Create",
          "style": "primary",
          "payload": {
            "action": "new_post_submit"
          }
        }
      ],
      "render": {
        "type": "Form",
        "props": {
          "children": {
            "type": "TextInput",
            "props": {
              "id": "title",
              "label": "Title"
            }
          }
        }
      }
    }
  }
}

New request after the user submits the form

POST https://bot-api.example.com/post HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "data": {
    "action": "new_post_submit",
    "form": {
      "title": "Hello world"
    }
  },
  "context": {
    "user_id": "<unique user ID>",
    "conversation_id": "<unique conversation ID>"
  }
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true,
  "message": "Post successfully created!",
  "data": {
    "type": "modal",
    "ui": {
      "buttons": [
        {
          "type": "close_modal",
          "title": "Cancel"
        },
        {
          "type": "post_payload",
          "title": "Create another",
          "style": "primary",
          "payload": {
            "action": "new_post_form"
          }
        }
      ]
    }
  }
}

The /post endpoint can be provided by your bot server in order to receive requests initiated by user interactions with your bots from a menu, message or modal described above.

All requests sent to the /post endpoint will have the shape described by the ClientRequest type and the bot server must return a valid BotResponse.

Data types

Whenever possible, the Mainframe client and server will provide strongly-typed payloads to the bot service, and expect responses of a certain shape.

Context types

The RequestContext is provided by the server as part of /post requests, in the context object of the payload.

RequestContext

type RequestContext = {
  user_id: string,
  conversation_id?: string,
  subscription_id?: string,
  subscription_token?: string,
}
Key Type Required
user_id string yes
conversation_id string when the request is sent from a conversation
subscription_id string when editing a subscription
subscription_token string when creating or editing a subscription

UI types

These types are the ones supported by the client to render custom UIs from the bots.

UIButton

type UIButton = {
  type: 'copy_url' | 'open_url' | 'open_modal' | 'close_modal' | 'form_post' | 'post_payload' | 'message_embed',
  title?: string,
  icon?: string,
  modalTitle?: string,
  payload?: Object,
  style?: 'primary' | 'secondary' | 'default',
  url?: string,
}

A generic type for buttons.

Key Type Required Value
type enum yes "copy_url", "open_url", "open_modal", "close_modal", "form_post", "post_payload" or "message_embed"
title string if type is not "copy_url" or "open_url" displayed in UI
payload Object when type is "open_modal", "message_embed" or "post_payload"
url string when type is "copy_url" or "open_url"
style enum no "primary" (main call to action), "secondary" or "default" (plain, default when not provided)
icon string no icon URL
modalTitle string no

Form types

type BasicValue = boolean | number | string
type FormOption = string | {label: string, value: BasicValue}
type FormValue = BasicValue | Array<BasicValue>
type FormData = {[id: string]: FormValue}

These types are used to describe the shape of the data defined and supported by the client when interacting with forms.

Name Type
BasicValue boolean, number or string
FormOption string or {label: string, value: BasicValue}
FormValue BasicValue or Array of BasicValue
FormData Object with keys of type string and values of type FormValue

Request types

These types represent the shape of the payload sent by the client when making a /post request.

RequestData

type JSON = boolean | number | string | Array<JSON> | {[string]: JSON}
type BotPayload = {[key: string]: JSON}
type RequestData = {
  ...BotPayload,
  form?: FormData,
}
Key Type Required
form FormData when triggered by button with type "form_post"
(any string) other data provided by the bot using the payload property when "payload" is provided

ClientRequest

type ClientRequest = {
  data: RequestData,
  context: RequestContext,
}
Key Type Required
data RequestData yes
context RequestContext yes

Response types

These types represent the shape of the payload that must be provided by the bot server as a result of a /post request.

UIPayload

type UIPayload = {
  version: 1,
  buttons?: Array<UIButton>,
  render?: RootComponent,
}
Key Type Required Value
version number yes 1 (only currently supported)
buttons Array of UIButton no
render RootComponent no

AuthenticationData

type AuthenticationData = {
  type: 'authentication',
  url: string,
  payload?: JSON,
}
Key Type Required Value Description
type string yes "authentication"
url string yes
payload Object no when provided, the client will make a /post request containing this payload after a successful authentication

EmbedData

type EmbedData = {
  type: 'embed',
  ui: UIPayload,
}
Key Type Required Value
type string yes "embed"
ui UIPayload yes

ModalData

type ModalData = {
  type: 'modal',
  ui: UIPayload,
  title?: string,
}
Key Type Required Value
type string yes "modal"
ui UIPayload yes
title string no

The optional title field can be set to change the modal's title in the client.

BotResponse

type BotResponse = {
  success: boolean,
  message?: string,
  data?: AuthenticationData | EmbedData | ModalData,
}
Key Type Required
success boolean yes
message string no
data AuthenticationData, EmbedData or ModalData no

Bot API

The Mainframe server will make HTTP calls to the following endpoints exposed by your bot API. Implementing these endpoints is optional, and only depends on the features you want to provide with your bot.

The Mainframe server will provide the following headers when making these requests:

  • Content-Type: application/json; charset=utf-8
Endpoint Required
/enable no
/disable when storing user data
/conversation_added no
/conversation_removed when storing conversation data
/delete_subscription if you setup a subscription
/post if you use custom UIs
/preview when a user request a preview
/mention when a participant mention the bot in a conversation

/enable

POST https://bot-api.example.com/enable HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "user_id": "<unique user ID>"
}

Called when an user enables your bot.

Request parameters

Key Type Required Description
user_id string yes Unique Mainframe identifier for the user

/disable

POST https://bot-api.example.com/disable HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "user_id": "<unique user ID>"
}

Called when an user disables your bot. All user data must be removed from your bot.

Request parameters

Key Type Required Description
user_id string yes Unique Mainframe identifier for the user

/conversation_added

POST https://bot-api.example.com/conversation_added HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "user_id": "<unique user ID>",
  "conversation_id": "<unique conversation ID>"
}

Called when your bot is added to a conversation.

Request parameters

Key Type Required Description
user_id string yes Unique Mainframe identifier for the user
conversation_id string yes Unique Mainframe identifier for the conversation

/conversation_removed

POST https://bot-api.example.com/conversation_removed HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "user_id": "<unique user ID>",
  "conversation_id": "<unique conversation ID>"
}

Called when your bot is removed from a conversation. All conversation data and subscriptions must be removed from your bot.

Request parameters

Key Type Required Description
user_id string yes Unique Mainframe identifier for the user
conversation_id string yes Unique Mainframe identifier for the conversation

/delete_subscription

POST https://bot-api.example.com/delete_subscription HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "subscription_id": "<unique subscription ID>"
}

Called when a subscription must be removed.

Request parameters

Key Type Required Description
subscription_id string yes Unique Mainframe identifier for the subscription

/post

POST https://bot-api.example.com/post HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "data": {...},
  "context": {...}
}

Called when an user presses a button generated by your bot, to trigger a specific action. Requests will be of type ClientRequest and responses must be of type BotResponse

Request parameters

Key Type Required Description
data RequestData yes Payload sent by the client
context RequestContext yes Contextual data sent by the server

/preview

POST https://bot-api.example.com/preview HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "user_id": "<unique user ID>",
  "link": "<URL to preview>"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true,
  "data": {...}
}

Called when a user for which your bot has been enabled requests a preview of an URL matching a preview domains your bot has been registered with.

Request parameters

Key Type Required Description
user_id string yes Unique Mainframe identifier for the user
link string yes The URL to generate a preview for.

Response parameters

If your bot cannot generate a payload it should return a response without a data field.

Key Type Required Description
success boolean yes true if the request succeeded, false otherwise
data UIPayload with a Message as the root component no The UIPayload of the preview.

/mention

POST https://bot-api.example.com/mention HTTP/1.1
Content-Type: application/json; charset=utf-8

{
  "user_id": "<unique user ID>",
  "conversation_id": "<Conversation ID>",
  "text": "<Message text>"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true
}

Called when a conversation participant has mentioned your bot.
This can either be an explicit mention (someone types @yourbot in a conversation your bot is added to), or implicitly in the specific conversation between your bot and the user having your bot enabled (in this case this endpoint will be called with any message from the user).

Request parameters

Key Type Required Description
user_id string yes Unique Mainframe identifier for the user
conversation_id string yes The Mainframe conversation identifier.
text string yes The complete text of the message containing the bot mention.

Mainframe server API

All HTTP requests to the Mainframe API must contain the following headers:

  • Content-Type: application/json; charset=utf-8
  • Authorization: Mainframe-Bot <secret> using the bot secret you received during registration.

/send_message

POST https://api.mainframe.com/bots/v1/send_message HTTP/1.1
Content-Type: application/json; charset=utf-8
Authorization: Mainframe-Bot <secret>

{
  "conversation_id": "<conversation ID>",
  "subscription_id": "<subscription ID>",
  "message": "<text message>",
}

https://api.mainframe.com/bots/v1/send_message

Send a message in a conversation

When calling this endpoint, the bot server should provide a subscription_id to indicate how the message is relevant to the conversation. While it is possible for the bot to send messages without a subscription_id, these messages might be rate-limited or even disabled to prevent abuse.

To send a more discrete message and reduce noise, the bot can send a micro message by setting the type to "micro". Note that micro messages must use the TextMessage component as root in the UIPayload instead of Message.

Request parameters

Parameter Type Required Description
conversation_id string yes Unique ID of the conversation to send the message to, provided by Mainframe
subscription_id string if the message is related to a subscription Unique ID of the relevant subscription
message string if data is not provided Text to display
data UIPayload if message is not provided Custom message UI
type string no Message type, can be "micro" or any future message types.

/setup_subscription

POST https://api.mainframe.com/bots/v1/setup_subscription HTTP/1.1
Content-Type: application/json; charset=utf-8
Authorization: Mainframe-Bot <secret>

{
  "subscription_token": "<provided token>",
  "label": "Alice's news feed"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true,
  "subscription_id": "<unique subscription ID>"
}

https://api.mainframe.com/bots/v1/setup_subscription

Create a subscription

Request parameters

Parameter Type Required Description
subscription_token string yes Token provided by Mainframe
label string yes Human-readable description for the subscription that will be displayed to users in the list of subscriptions in a conversation, and should briefly describe what kind of events will be provided via the subscription

/edit_subscription

POST https://api.mainframe.com/bots/v1/edit_subscription HTTP/1.1
Content-Type: application/json; charset=utf-8
Authorization: Mainframe-Bot <secret>

{
  "subscription_token": "<provided token>",
  "label": "Bob's news feed"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true,
  "subscription_id": "<unique subscription ID>"
}

https://api.mainframe.com/bots/v1/edit_subscription

Edit a subscription

Request parameters

Parameter Type Required Description
subscription_token string yes Token provided by Mainframe
label string no Human-readable description for the subscription that will be displayed to users in the list of subscriptions in a conversation, and should briefly describe what kind of events will be provided via the subscription; If provided, it will override the existing label

/delete_subscription

POST https://api.mainframe.com/bots/v1/delete_subscription HTTP/1.1
Content-Type: application/json; charset=utf-8
Authorization: Mainframe-Bot <secret>

{
  "conversation_id": "<conversation ID>",
  "subscription_id": "<subscription ID>",
  "message": "<text message>"
}
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "success": true
}

https://api.mainframe.com/bots/v1/delete_subscription

Delete a subscription

Request parameters

Parameter Type Required Description
conversation_id string yes Unique ID of the conversation to remove the subscription from
subscription_id string yes Unique ID of the relevant subscription
message string no Optional message to post to the conversation (to explain the reason for removal)

Mainframe client UI

The Mainframe client is able to display custom UIs provided by your bot. These UIs are of two main types: buttons and components.

Buttons

Buttons are the basis of user interactions in the Mainframe client. They are used to trigger specific client-side behaviors based on their type. Buttons can be used in the following contexts, that affect their supported behavior and UI options:

Some components can also act in a similar way as buttons to handle user interactions:

Menu buttons screenshot

Properties

Name Type Required Description
type enum yes one of "copy_url", "open_url", "open_modal", "message_embed", or "post_payload"
title string yes displayed in UI
icon string yes URL of the icon displayed in the UI
payload Object if type is "open_modal", "message_embed" or "post_payload" data sent to the bot when making a request
url string if type is "copy_url" or "open_url" URL to copy or open
modalTitle string no optional title of the modal when type is "open_modal"

Message button

Message buttons screenshot

Properties

Name Type Required Description
type enum yes one of "copy_url", "open_url", "open_modal" or "post_payload"
title string if type is not "copy_url" or "open_url" displayed in UI
payload Object if type is "open_modal" or "post_payload" data sent to the bot when making a request
url string if type is "copy_url" or "open_url" URL to copy or open
modalTitle string no optional title of the modal when type is "open_modal"

Modal buttons screenshot

Properties

Name Type Required Description
type enum yes one of "copy_url", "open_url", "close_modal", "post_payload", "message_embed", or "form_post"
title string if type is not "copy_url" or "open_url" displayed in UI
payload Object if type is "post_payload" or "message_embed" data sent to the bot when making a request
url string if type is "copy_url" or "open_url" URL to copy or open
style enum no one of "primary" (main call to action), "secondary" or "default" (plain, default when not provided)

Components

The UI can be described by "components" objects following React's model. These components can contain properties that are handled by the client in specific ways.

The components can be separated in two main groups: "root" components that can only be used as root of the component tree, containing children, and "child" components that can only be used as children of other components.

Root components

These components must be used as the top-level component provided to the UIPayload:

  • Dialog for complex displays and button-type interactions
  • Form to collect user input in a modal
  • Message for messages and embeds, useful for simple displays and button-type interactions
  • TextMessage for simple "micro" messages (text only)

Dialog component

Generic root container for modal dialogs that do not require user inputs. Use the Form component if you need the user to input data.

Name Type Required Description
children Author, AvatarList, IconTextGroup, Image, LinkPreview, List, MediaGallery, Text or VideoLinkPreview yes
noPadding boolean no removes the padding inside the Dialog

Form component

Top level component to handle data from its supported children components.
The Text component can be used to provide additional information to the user if needed.

Properties

Name Type Required Description
children CheckboxGroup, CheckboxItem, Dropdown, MultiLineInput, MultiSelect, RadioButtonSelect, Text or TextInput yes
payload Object no any additional to be included in the form submission
data FormData no key-value pairs used to fill the displayed children, matching their id, see the form types for more information

Message component

Root container for the UI that goes inside bot messages and embeds, similar to how all form components get nested inside Form.
For text-only messages, prefer using the TextMessage root component to render a simpler message UI.

Name Type Required
children Author, AvatarList, IconTextGroup, Image, LinkPreview, Text or VideoLinkPreview yes

TextMessage component

Root container for a text-only message, containing at least one child Text component. Use this container as an alternative to the Message root component to render a simpler message when sending "micro" messages.

Properties

Name Type Required
children Text yes

Child components

These components can only be used as a child of another component, either a root component or another child component itself:

Author component

Author screenshot

A component that can represent a user with simple user data.

Properties

Name Type Required Description
displayName string yes renders the main text
username string yes this is more subtle/italics
avatarUrl string no to render an avatar
isCircle boolean no if true then it will be circle avatar

AvatarList component

AvatarList screenshot

A component that represents a horizontal row/list of images.

Properties

Name Type Required Description
avatars Array of string yes the strings are the avatar URLs
isCircle boolean no if true then avatars will be circles

CheckboxGroup component

A group of CheckboxItems but with a main label above the grouping, can only be used a a child of a Form and its children can only be CheckboxItems.

Properties

Name Type Required Description
title string yes a label for the inputs, positioned directly above the checkboxes
children CheckboxItem yes

CheckboxItem component

A text label with a checkbox positioned at the front of the label, can only be used a a child of a CheckboxGroup. The produced FormValue for this input will be a boolean based on the CheckboxItem being checked or not.

Properties

Name Type Required Description
id string yes unique identifier for this form field
label string yes a label for the checkbox, positioned directly to the right of the checkbox

A component where users can only select a single option, can only be used a a child of a Form.

Properties

Name Type Required Description
id string yes unique identifier for this form field
label string yes a label positioned directly above component
options Array of FormOption yes
disabled boolean no if the component can be edited or not
placeholder string no directly inside component, default is "Select an option…"

IconTextGroup component

IconTextGroup screenshot

A component that renders a group of image, primary text and secondary text.
The image provided by imageUrl will be resized to fit its square container, preserving aspect ratio.

Properties

Name Type Required Description
primaryText string yes the primary text
secondaryText string no secondary text
imageUrl string no URL of the image

Image component

Image screenshot

A component that renders an image.

Properties

Name Type Required Description
imageUrl string yes the image URL
height number yes height of the image
width number yes width of the image
allowOpenFullImage boolean no allow the image to be opened in full view
fillContainer boolean no makes the image fill the container
backgroundColor string no background color displayed while the image is loading

LinkPreview component

LinkPreview screenshot

A component that represents a link on the web (but can be used in different ways also).

Properties

Name Type Required Description
title string yes the primary text headline
url string yes the link to open if user clicks
excerpt string no text to show preview of link
imageUrl string no URL of the image that represents the link
domainIconUrl string no URL of the image that represents the domain
domainName string no the domain

List component

Container for ListItem children.

Name Type Required
children ListItem yes

ListItem component

Item container to be used as a child of a List component.
When its type property is set, the ListItem acts as a Button.

Name Type Required Description
children Author, AvatarList, IconTextGroup, Image, LinkPreview, Text or VideoLinkPreview yes
type enum no one of "copy_url", "open_url", "open_modal", "message_embed", or "post_payload"
payload Object if type is "open_modal", "message_embed" or "post_payload" data sent to the bot when making a request
url string if type is "copy_url" or "open_url" URL to copy or open
modalTitle string no optional title of the modal when type is "open_modal"

MediaGallery component

Container for a list of MediaItem children, supporting interactions on its children based on the provided type when provided.

Name Type Required Description
children MediaItem yes
showSquareImages boolean no When true displays all the children MediaItem images in a square container, defaults to false

MediaItem component

A child of MediaGallery displaying an image and possibly supporting interactions based on the parent MediaGallery type when provided.

Name Type Required Description
imageUrl string yes the image URL
height number if the parent MediaGallery showSquareImages is false or not provided height of the image
width number if the parent MediaGallery showSquareImages is false or not provided width of the image
type enum no one of "copy_url", "open_url", "open_modal", "message_embed" or "post_payload"
payload Object when type is "open_modal", "message_embed" or "post_payload" data sent to the bot when making a request
url string when type is "copy_url" or "open_url" URL to copy or open
modalTitle string no optional title of the modal when the type is "open_modal"
isSelected boolean no set to true if the item is selected, defaults to false
selectedBorderColor string no border color used when isSelected is true
backgroundColor string no background color displayed while the image is loading

MultiLineInput component

Text input for when you want the text to be wrapped and to display multiple lines, can only be used a a child of a Form.

Properties

Name Type Required Description
id string yes unique identifier for this form field
label string yes a label for the input, positioned directly above the text input
errorFeedback boolean or string no if there is an error with the input, will highlight red border/red text and display the feedback text if a string is provided

MultiSelect component

A component where users can select multiple options, can only be used a a child of a Form. The produced FormValue will be an Array of BasicValue of the selected options.

Properties

Name Type Required Description
id string yes unique identifier for this form field
label string yes a label positioned directly above the component
options Array of FormOption yes
disabled boolean no if the component can be edited or not

RadioButtonSelect component

A selector displaying a list of radio buttons with a main label above the grouping.

Properties

Name Type Required Description
id string yes unique identifier for this form field
title string yes a label positioned directly above all the radio buttons
options Array of FormOption yes

Text component

Text screenshot

Basic text component, containing a text string or other text components.

All text components (Text, TextLink, TextStyle...) are displayed inline by their wrapping Text parent. If you need to display text over multiple lines, make sure to adapt the component hierarchy accordingly, as shown in the examples.

The following text message will be displayed in a single line

{
  "type": "TextMessage",
  "props": {
    "children": {
      "type": "Text",
      "props": {
        "children": [
          "Hello ",
          {
            "type": "TextStyle",
            "props": {
              "type": "bold",
              "children": "bot"
            }
          }
        ]
      }
    }
  }
}

The following text message will be displayed over two lines

{
  "type": "TextMessage",
  "props": {
    "children": [
      {
        "type": "Text",
        "props": {
          "children": "Hello "
        },
      },
      {
        "type": "Text",
        "props": {
          "children": {
            "type": "TextStyle",
            "props": {
              "type": "bold",
              "children": "bot"
            }
          }
        },
      }
    ]
  }
}

Properties

Name Type Required Description
children string, Text, TextButton, TextHighlight, TextLink, TextStyle or TextSubtle yes can be normal string to be rendered or one of the supported nested components: Text, TextButton, TextHighlight, TextLink, TextStyle and TextSubtle.

TextButton component

Text component acting as a button to handle interactions.

Properties

Name Type Required Description
children string yes string to be rendered
type enum no one of "copy_url", "open_url", "open_modal" or "post_payload"
payload Object if type is "open_modal" or "post_payload" data sent to the bot when making a request
url string if type is "copy_url" or "open_url" URL to copy or open
modalTitle string no optional title of the modal when type is "open_modal"

TextHighlight component

A text with a custom color and highlight (background) color.

Properties

Name Type Required Description
children string, TextLink or TextStyle yes this is the text rendered, can be string or one of these nested components: TextLink or TextStyle
textColor string no Web color for the text
highlightColor string no Web color for the background

TextInput component

A single line text input, can only be used a a child of a Form.

Properties

Name Type Required Description
id string yes unique identifier for this form field
label string yes a label for the input, positioned directly above the text input
prefix string no show a string before the text input, like "@" for username input
buttonTitle string no a small button at end of text input, like "Add" or "Invite" or "Check"
buttonType enum if buttonTitle is set only possible value is "post_payload"
buttonPayload Object if buttonType is "post_payload"
errorFeedback boolean or string no if there is an error with the input, will highlight red border/red text and display the feedback text if a string is provided

TextLink screenshot

Text field which is a link to an external URL.

Properties

Name Type Required Description
children string yes this is the text rendered, no other components can be nested in here
url string yes external URL to open when user clicks on this text component
noStyle boolean no if true then the UI will not make it super obvious that it’s a link i.e. underline, change color, etc
noEmojify boolean no if true then it will not emojify the string. An example of when to use this would be if the string is an actual url format and we might want to preserve http://etc for if someone wants to copy URL, etc)

TextLinks inside TextSubtle screenshot

On the side is an example of TextLinks nested inside TextSubtle component where noStyle is applied. One links to the board, another to the list (which I know doesn’t actually exist in Trello but just an example):

TextStyle component

TextStyle screenshot

Styled text field.

Properties

Name Type Required Description
children string yes this is the text rendered, no other components can be nested in here
type enum yes possible values are "bold", "code", "italic" and "strike"

TextSubtle component

TextSubtle screenshot

Basic text field but less prominent (smaller font size, italics, gray, etc).

Properties

Name Type Required Description
children string or TextLink yes can be normal string to be rendered or nested TextLink. Note, any TextLink components nested in here will automatically have noStyle prop.

VideoLinkPreview component

LinkPreview screenshot

A component that represents a link of a video on the web (but can be used in different ways also).

Properties

Name Type Required Description
title string yes the primary text headline
url string yes the link to open if user clicks
author string no text to show the author of the video
imageUrl string no URL of the image that represents the link
imageWidth number if imageUrl if provided Width of the image thumbnail
imageHeight number if imageUrl if provided Height of the image thumbnail
domainIconUrl string no URL of the image that represents the domain
domainName string no the domain
videoProvider enum no Currently the desktop app can embed Youtube or Vimeo videos, this prop accepts vimeo or youtube as valid values
videoId string if videoProvider if provided Used along with videoProvider. Should contain the Youtube or Vimeo video ID, ex: The ID for this youtube url: https://www.youtube.com/watch?v=hhpK96Nkc1Y would be: hhpK96Nkc1Y; and for this vimeo url: https://vimeo.com/17382852 would be 17382852.
videoWidth number if videoProvider if provided Width of the video player
videoHeight number if videoProvider if provided Height of the video player
noPlayButton boolean no When set to true, it will not show the play button overlaying the video thumbnail

Support

Get in touch directly with Mainframe developers by joining our support channel in Mainframe!

If you see any error with this documentation or want to provide any other feedback about it, please open an issue or pull request in our GitHub repository.