Creating a Partner Channel

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.

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.

We highly recommend you download our Postman collection to help with the development process.

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.

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.

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.

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, 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.

Receiving messages from Front

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, and 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"
}

In some cases, however, 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

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?