npm package: @archer2024/intercom-api
Description: The Intercom API client for Node.js and the browser for Archer Affiliates.
Author: Kashan Ahmad
Latest version: 0.0.5

# Intercom API 🍞

## by and for Archer Affiliates

Template used: [Crust 🍞](https://github.com/sassywares/crust)

This is a simple API for integrating [Intercom](https://intercom.com) with Archer Affiliates. It is built using TypeScript, Axios, and Zod, and provides a simple set of types and methods required to interact with the Intercom API.

## Features

- Messenger Script
- Ticketing

## Getting Started

Whenever you intend to integrate another app with intercom using this API, follow these steps:

### 1. Install this package:

```bash
npm install @archer2024/intercom-api
```

### 2. Setup your environment variables, we need only two:

```bash
INTERCOM_APP_ID=your_app_id
INTERCOM_ACCESS_TOKEN=your_access_token
```

You can find the `INTERCOM_APP_ID` in your Intercom settings, and the `INTERCOM_ACCESS_TOKEN` in your Intercom developer workspace settings.

### 3. Setup the intercom messenger to have a chat with your users.

Go to your root HTML file, \_document.jsx in case of Next.js, import the `generateIntercomScript` function from `@archer2024/intercom-api/client`:

```js
import { generateIntercomScript } from "@archer2024/intercom-api/client";
```

This function generates a stringified script that you can add to your HTML file using a script tag, like so:

```html
<script>
  {
    generateIntercomScript({ appId: process.env.INTERCOM_APP_ID });
  }
</script>
```

Or in React, using the `dangerouslySetInnerHTML` prop:

```jsx
<script
  dangerouslySetInnerHTML={{
    __html: generateIntercomScript({ appId: process.env.INTERCOM_APP_ID }),
  }}
/>
```

Now, start your dev server and, if everything is set up correctly, you should see the little FAB on the bottom right corner of your screen, click it and voila! You can chat with your users.

### 4. Integrate all your contact forms with Intercom.

For this, we use Intercom's ticketing system, each contact form submission creates a ticket which is then handled using the Intercom dashboard. This is a multi-step process, follow carefully:

#### The Server Side

- First, understand that Intercom doesn't allow clients/browsers to directly interact with its API, so we need a server to act as a middleman. This is where the `@archer2024/intercom-api/server` package comes in.

- Setup the server endpoint, you can use whatever server framework you're working with, as long as you get the endpoint right. For now, I've only added the ability to have one fixed endpoint to create tickets, which is `/api/intercom/tickets`. You can contribute to this package and make the endpoint a parameter if you want, I'd be happy to merge your PR.

- Have a POST request handler at the mentioned endpoint, and pass the request body to the `createTicket` function from `@archer2024/intercom-api/server`. This is an asynchronous function so you can either use promises or async/await and handle errors. It will simply create a ticket in Intercom and return the response:

```js
import { createTicket } from "@archer2024/intercom-api/server";
```

- The request body is always of the type `NewTicket`, which is basically an exact copy of the Intercom API's ticket object. You can find the type in the `@archer2024/intercom-api/tickets` package. For the sake of simplicity, here's the actual type:

```ts
type NewUserTicket = {
  contacts: [
    {
      email: string;
    }
  ];
  ticket_type_id: "1" | "2" | "3" | "4" | "5" | "6" | "7";
  ticket_attributes: {
    _default_title_: string;
    _default_description_?: string | undefined;
    user_id?: string;
    username?: string;
  };
};
```

This is the request object, here's a breakdown:

1. `contacts` is an array of objects, except you must always send one array with one object with one email. This is the email of the user who submitted the form.

2. `ticket_type_id` is the type of ticket you want to create, you can manage ticket types from the Intercom dashboard, Archer, as of writing this, has tickets of 5 types:

```ts
export const ticketTypeWebsiteId = "1";
export const ticketTypeBugId = "2";
export const ticketTypeFeatureId = "3";
export const ticketTypeInternalId = "4";
export const ticketTypeAffiliateId = "5";
export const ticketTypeBrandId = "6";
export const ticketTypePortalId = "7";
```

Whenever you send a request, import one of these from the `@archer2024/intercom-api/tickets` package and use it as the `ticket_type_id`, don't ever use raw strings, that's just bad practice.

3. `ticket_attributes` is an object with two keys, `_default_title_` and `_default_description_`. The title is always required, the description is optional. You should also send `user_id` and a `username` in case of authenticated users, but these are optional.

4. This is what the final server handler would look like if you were using Next.js with the pages directory:

- Create the Axios Instance made specifically for Intercom API, this is done using the `generateIntercomApi` function from `@archer2024/intercom-api/shared`. This function takes an object with the `accessToken` property, which is your Intercom access token, and returns an Axios instance with the necessary headers to interact with the Intercom API. You can use this instance to make requests to the Intercom API anywhere from the server.

```ts
/pages/aip / intercom / tickets.ts;

import { createTicket } from "@archer2024/intercom-api/server";
import {
  generateIntercomApi,
  IntercomApiResponse,
} from "@archer2024/intercom-api/shared";
import { ZodError } from "zod";
import type { NextApiRequest, NextApiResponse } from "next";

const api = generateIntercomApi({
  accessToken: process.env.INTERCOM_ACCESS_TOKEN,
});

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<IntercomApiResponse>
) {
  if (req.method === "POST") {
    try {
      // Create the ticket on Intercom
      const { data } = await createTicket({ api, newTicket: req.body });

      // Process a POST request
      res.status(200).json({ message: "Ticket created", data });
    } catch (e: unknown) {
      if (e instanceof ZodError) {
        res.status(400).json({ message: "Bad Request", issues: e.errors });
      } else {
        res.status(500).json({ message: "Internal server error" });
      }
    }
  }
}
```

Note that we forward the whole request body as it is to the `createTicket` function, this is since the functions uses a Zod schema underneath to match the `NewTicket` type, and will throw an error if the request body doesn't match the type, so you don't need to worry about anything.

#### The Client Side

On the client side, you have a similar function named `createTicket` which takes the exact same `NewTicket` type as the only argument and sends a POST request to the server endpoint. This function is also asynchronous, so you can use promises or async/await and handle errors. It will return the response from the server:

```js
import { createTicket } from "@archer2024/intercom-api/client";
```

Here's how you can use it in a React component:

```jsx
import { createTicket } from "@archer2024/intercom-api/client";
import { ticketTypeWebsiteId } from "@archer2024/intercom-api/tickets";

export default function ContactForm() {
  const handleSubmit = async (e) => {
    e.preventDefault();

    const form = e.target;

    const newTicket = {
      contacts: [{ email: form.email.value }],
      ticket_type_id: ticketTypeWebsiteId,
      ticket_attributes: {
        _default_title_: form.subject.value,
        _default_description_: form.message.value,
      },
    };

    try {
      const response = await createTicket(newTicket);
      console.log(response);
    } catch (e) {
      console.error(e);
    }
  };
}
```

This function parses the newTicket using the same `NewTicket` Zod schema, and sends a POST request to the server endpoint with the parsed object as the request body. The server then creates a ticket on Intercom and returns the response. This ensures double validation, once on the client side and once on the server side.

And that's it! You've successfully integrated Intercom with your app. If you have any questions, feel free to ask, my email is [kashanahmad.me@gmail.com](mailto:kashanahmad.me@gmail.com) and I'm always happy to help.

## Contributing

We are always looking for ways to improve and make ourselves better. If you have any suggestions, ideas, or feedback, please open an issue or a pull request.

## License

This is open source software released under the [MIT License](LICENSE). We encourage you to use, modify, and distribute it as you see fit.