Fundamentals of Partner Channels

Partner channels are useful for establishing a communication channel in Front with a variety of third party data sources, from SMS to phone call logs to live chat. Partner channels also allow you to publish your integration publicly to all Front customers, although this is optional (Front customers can also build partner channels purely for in-house use). For details on when to use a partner channel vs a custom channel, please see our Overview page. This guide will walk through all the necessary steps to build a partner channel.

📘

Replies to channel messages must use the same channel.

You cannot receive an inbound message through a channel, and then reply to the message via another Front inbox such as your personal email account or a team inbox. If you would like to receive a message via a non-native channel and then reply to the message via another Front inbox, use the Import Message API endpoint instead.

Postman collection

We recommend using our Postman collection for Partner Channels to facilitate your development.

Requesting a Partner Channel

The first step is to submit the partner channel request form. The form asks for some important information we’ll use to create a channel type for you. We’ll get back to you within a few days and provide you with a channelTypeId and a secretKey that you’ll need to use when building your channel. At that point, your channel will also be available for use in your instance of Front only (by navigating to Settings → Inboxes → [Desired Inbox] → Channels → Add channel).

Note that you can submit the form multiple times — we often see our partners first submit an initial application to set up a testing/staging channel, and then submit a second time to create the production channel instance after they’ve had a chance to build everything out using the testing one.

Composer Types for Partner Channels

As of April 2022, new or existing channel types have optional access to using an advanced composer that supports most Markdown styling options. If you have already built a partner channel with Front and would like to upgrade it to the advanced composer, please email [email protected]

When you’re entering the information to create your own channel type, you’ll have the option to choose the type of composer for your channel type. The two options provided are Basic and Advanced.

With a Basic composer, you’ll have the ability to compose and send only plain text content along with emojis and attachments while still retaining the ability to receive rich text messages.

10601060

With an Advanced composer, you’ll have the ability to compose and send a richer message. The following features are supported (along with their respective keyboard shortcuts).

  1. Bolding
  2. Italics
  3. Linking
  4. Strikethroughs
  5. Lists (numbered / bulleted)
  6. Block quotes
  7. Emojis
  8. Attachments
10541054

If you're using a partner channel with an advanced composer and access messages sent through that channel via the API, please use the "body" field of the message to fetch the message content with all its data and formatting preserved.

Channel Authorization

Now that you have a channel type set up, you’ll need to build support for a few key functions. The first is channel authorization, which occurs when a Front user attempts to connect an instance of your channel from their Front settings.

If you set your authentication method to “API Token”, users will see the following when they attempt to connect your channel. If you haven’t already, you’ll need to set up some kind of mechanism to allow users to create an API token for your service. Note that the API Key that users are expected to submit here is not the same as the secret key we provided you when getting your channel type configured. This key is expected to be something that your users can get directly from you, and will allow you to identify which user is trying to connect the channel to Front.

17841784

If you set your authentication method to “OAuth”, users will see the following when they attempt to connect your channel. The blue button will redirect the user to the OAuth URL you provided in the channel application. We’ll use the OAuth Client Secret and OAuth Refresh Url to retrieve an access token.

17081708

At this point, whether your channel is using API token or OAuth authentication, Front will have an access token it can use to make requests to your server.
Front will use that bearer token to POST to the Webhook URL you supplied in the channel application form. The body of the request will look like:

{
  "type": "authorization",
  "payload": {
    "channel_id": "cha_123"
  }
}

Your system will need to respond to this message and other messages from Front within 7 seconds. After 7 seconds, Front will timeout and return an error to the user, regardless of any response received after the 7 second timeout.

Responding to Authentication

Once you’ve verified that the request is valid, your server should store the channel_id in the authorization payload and associate it with the owner of the token. This will allow you to send and receive messages in the future. You’ll also need to send a 200 response to the authorization request with the following:

{
  "type": "success",
  "webhook_url": "https://webhook.company.com/..."
}

The webhook URL you provide here will be used by Front to POST new messages sent from Front using the channel instance the user created. It does not necessarily have to be a unique webhook for each channel instance. It also does not necessarily have to be the same as the webhook URL you provided in the channel application form, which is used when sending channel authorization requests.

You can test that your server is properly handling channel creation by using the “Authorization” endpoint under “Your Webhook Endpoints” in the Postman collection for Partner Channels.

Sending and Receiving Messages

Managing threading

Threading defines how individual messages will be “threaded” into a single conversation. Some channels thread simply by the sender of a message, while others thread conversations only within a particular time frame, or use some other custom logic. With the Channel API, you can control threading through the external_conversation_id, which must be set when sending messages into the channel. Messages with the same external_conversation_id will be threaded together. Note that this value is different from a message’s external_id, which is simply a unique identifier of a single message.

Creating messages in Front

There are two endpoints that can be used to create a message in Front for your channel — the
Sync inbound message endpoint and the Sync outbound message endpoint. The sync inbound message endpoint should be used when you are trying to send an inbound message to the channel. For example, a lead that has just written a message into a website live chat widget. The sync outbound message endpoint should be used to import a message that was sent from the channel. This is useful if outbounds might be sent by the channel outside the context of Front — for example, importing a message that a bot replied to the lead, so that users in Front can see the full history of the conversation.

In either case, you will need to authenticate requests to Front by setting a bearer token generated using your secret key, channel type id, and the id of the channel instance you are trying to send to. Sample code for doing so can be found in the pre-request script of the Postman collection for Partner Channels, or via this link. Note that you can use that bearer token to make requests to any of the Channel API endpoints as well as Core API routes of the following formats:

  • /conversations/:conversation_id*
  • /messages/:message_id*

A successful request to the Sync inbound message or Sync outbound message endpoints will result in a response that includes a message_uid you can use to fetch the full message and conversation created in Front. To do so, use the Get message endpoint and use the uid as a resource alias . For example, https://api2.frontapp.com/messages/alt:uid:abcd1234. Directly fetching the message this way is not necessary though, because Front will also send message_imported payload to the channel-instance-specific webhook URL to let you know about the successful import.

{
    "type": "message_imported",
  "payload": {
    [MESSAGE BODY]
  },
  "metadata": {
    // Will eventually be deprecated in favor of "external_conversation_ids"
    "external_conversation_id": string,
    // A single Front conversation may have multiple external conversation
    // ids because conversations in Front can be merged.
    "external_conversation_ids": [string]
  }
}

You can test that your server is properly sending messages to Front by using the “Inbound Message” and “Outbound Message” endpoints in the Postman collection for Partner Channels.

Receiving messages from Front

There are two ways your channel might receive messages from Front:

  1. Messages sent manually by a user
  2. Auto-reply messages

1. Manually-sent messages

When a user in Front sends a new outbound message or replies to an inbound message using your channel, Front will POST the following to the channel-instance-specific webhook URL:

{
  "type": "message",
  "payload": {
    [MESSAGE BODY]
  }
}

The payload will match the Message schema, an example of which is provided below:

{
  "_links": {
    "self": "https://api2.frontapp.com/messages/msg_55c8c149",
    "related": {
      "conversation": "https://api2.frontapp.com/conversations/cnv_55c8c149",
      "message_replied_to": "https://api2.frontapp.com/messages/msg_1ab23cd4"
    }
  },
  "id": "msg_55c8c149",
  "type": "email",
  "is_inbound": true,
  "draft_mode": null,
  "created_at": 1453770984.123,
  "blurb": "Anything less than immortality is a...",
  "author": {
    "_links": {
      "self": "https://api2.frontapp.com/teammates/tea_55c8c149",
      "related": {
        "inboxes": "https://api2.frontapp.com/teammates/tea_55c8c149/inboxes",
        "conversations": "https://api2.frontapp.com/teammates/tea_55c8c149/conversations"
      }
    },
    "id": "tea_55c8c149",
    "email": "[email protected]",
    "username": "leela",
    "first_name": "Leela",
    "last_name": "Turanga",
    "is_admin": true,
    "is_available": true,
    "is_blocked": false
  },
  "recipients": [
    {
      "_links": {
        "related": {
          "contact": "https://api2.frontapp.com/contacts/crd_55c8c149"
        }
      },
      "handle": "[email protected]",
      "role": "to"
    }
  ],
  "body": "Anything less than immortality is a complete waste of time.",
  "text": "Anything less than immortality is a complete waste of time.",
  "attachments": [
    {
      "filename": "attachment.jpg",
      "url": "https://api2.frontapp.com/download/fil_55c8c149",
      "content_type": "image/jpeg",
      "size": 10000,
      "metadata": {
        "is_inline": true,
        "cid": "123456789"
      }
    }
  ],
  "metadata": {}
}

Be sure to check that the type of payload is message, create the message in your system, and respond with an external_id and external_conversation_id that you want to associate the message with:

{
  "type": "success",
  "external_id": "external_message_{{$randomInt}}",
  "external_conversation_id": "external_conversation_1"
}

2. Auto-reply messages

Front allows users to create auto-reply rules, which automatically send a response upon receiving an inbound message.

Auto-reply messages differ from manually-sent messages in certain ways, related to data structure and the sequence of events:

  • An auto-reply message has not yet actually been sent by the time Front sends the event to your channel. This means that an auto-reply event has a different payload than a message event. An example auto-reply event is shown below.
  • After your channel responds with the external IDs, your channel will receive a message_imported event with the full message, as described above.

When an auto-reply message is sent, your channel should take the following steps:

  1. Expect a request like the following. (Note the different payload when compared to a manually-sent message payload.)
  2. Create the message in your system
  3. Respond with the same information as with the message events; this will be used to associate the message with a conversation. As with message events, both external_id and external_conversation_id are required).
  4. Wait for a message_imported event from Front, which will include the full message payload.
{
  "type": "message_autoreply",
  "payload": {
    [AUTOREPLY MESSAGE BODY]
  }
}

This time, the request type is message_autoreply, and the payload will have a different structure. Here's an example payload:

{
  "_links": {
    "related": {
      "conversation": "https://api2.frontapp.com/conversations/cnv_55c8c149",
      "message_replied_to": "https://api2.frontapp.com/messages/msg_1ab23cd4"
    }
  },
  "type": "auto_reply",
  "is_inbound": false,
  "created_at": 1453770984.123,
  "body": "I'll get back to you as soon as possible.",
  "text": "I'll get back to you as soon as possible.",
  "recipients": [
    {
      "_links": {
        "related": {
          "contact": "https://api2.frontapp.com/contacts/crd_55c8c149"
        }
      },
      "handle": "[email protected]",
      "role": "to"
    }
  ],
  "attachments": [
    {
      "filename": "attachment.jpg",
      "url": "https://api2.frontapp.com/download/fil_55c8c149",
      "content_type": "image/jpeg",
      "size": 10000,
      "metadata": {
        "is_inline": true,
        "cid": "123456789"
      }
    }
  ]
}

Though the payload is different than the payload for a message event, the expected response is the same:

{
  "type": "success",
  "external_id": "external_message_{{$randomInt}}",
  "external_conversation_id": "external_conversation_1"
}

Handling errors

In some cases, there might be errors that happen on your channel when Front POSTs a message to the provided webhook. To help debug these issues, and to convey failures to users, you can include a certain error code and message in your response. If you wish to indicate that an error occurred while sending a message, you can respond in the following format.

{
  "type": [ERROR_CODE],
  "message": [MESSAGE]
}

If type is any of the following, it will indicate in the UI that the message failed to send.

bad_request
authentication_required
forbidden
not_found
request_timeout
too_many_requests
internal_error

Including the message property is optional. If you do include it, that string will be presented to users as the reason that the message failed to send, pictured below

16001600

Updating status through the API

Partner channels can become unauthenticated with their third-party services. While typically Front will detect this automatically and set the channel to offline, in the case of low-volume channels this may not happen automatically. The partner channel PATCH endpoint can be used to update the channel's status to offline manually, which will prompt users to re-authenticate immediately instead of waiting for drafts to fail to send.

This endpoint should be called by the channel itself using the channel's token in the same way as the sync inbound/outbound message endpoints are called.

When the channel is set to offline, users will see a popup in the lower-left corner of Front that looks something like this:

610610

offline channel popup

When the 'View Settings' button is clicked, it will take the user into the channel settings where they can begin the process to re-authenticate the channel. That looks something like this:

12521252

Deletion (optional)

When a user deletes an instance of your channel, Front will send the following to your webhook URL:

{
  "type": "delete",
  "payload": {
    "channel_id": "cha_123"
  }
}

Handling this case is optional, but will allow you to keep up to date with user’s channel usage.

Security

To verify that this and other messages sent from Front for your channel are legitimate, you can validate the message signature before accepting it into your system.

The requests made to your webhook server will include 2 headers: X-Front-Signature and X-Front-Request-Timestamp. First, check that the timestamp says the request was made recently in order to prevent replay attacks. We recommend 5 minutes as the maximum time before rejecting a message.

  1. Retrieve the X-Front-Request-Timestamp header on the HTTP request and the body of the request.
  2. Concatenate the timestamp and the JSON stringified body of the request to form a string. Use a colon as the delimiter between the two elements.
  3. Using HMAC SHA256, hash the above string, using your Channel Type Secret Key as the key.

This should match the X-Front-Signature header. If it does not, you should not trust this message. See our sample code in Typescript for how to validate a message and generate a token.

Publishing

At this point, you’re all set with the technical implementation! If you’re looking to publish your channel as a public partner integration for all Front customers, simply reply to the existing thread you had with our team when we provided your channel id and secret. We’ll work with you to get some marketing content ready for our integrations page, and then publish the integration.

That’s it! If you have any questions, feel free to reach out to us at [email protected].


Did this page help you?