Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Discussion options

V6 Release

The Intercom team is excited to announce a new and improved TypeScript SDK, currently available as an alpha version. Check out the API reference here.

During this time, we hope to gather feedback from the Intercom community to help drive the direction of the latest API changes.

Please feel free to leave in any suggestions here to improve the experience for everyone!

Installation

Install the latest alpha by running the following command:

npm install intercom-client@alpha

This will install a version that looks like the following:

  • 6.0.0-alpha
  • 6.0.0-alpha1
  • 6.0.0-alpha2

New Features

1. Strongly typed

All types and endpoints are strongly typed and up to date with Intercom’s latest API.

In version 5.0.0, some of the SDK types included any and unknown properties, which put more onus on the caller to determine what type was expected.

But with the new alpha, you’ll always know exactly what type you’re working with. For example, consider the RequestOptions type:

Before

interface RequestOptions {
    url: string;
    data?: any
    params?: any;
}

After

interface RequestOptions {
    /** The maximum time to wait for a response in seconds. */
    timeoutInSeconds?: number;
    /** The number of times to retry the request. Defaults to 2. */
    maxRetries?: number;
    /** A hook to abort the request. */
    abortSignal?: AbortSignal;
    /** Override the Intercom-Version header */
    version?:
        | "1.0"
        | "1.1"
        | "1.2"
        | "1.3"
        | "1.4"
        | "2.0"
        | "2.1"
        | "2.2"
        | "2.3"
        | "2.4"
        | "2.5"
        | "2.6"
        | "2.7"
        | "2.8"
        | "2.9"
        | "2.10"
        | "2.11"
        | "Unstable";
}

2. Rich documentation

The new SDK includes in-lined documentation on both endpoints and object properties. This helps the user recognize exactly what parameters need to be specified and allows them to iterate even faster.

For example, consider the following endpoint documentation:

/**
 * You can update the details of a single article by making a PUT request to `https://api.intercom.io/articles/<id>`.
 *
 * @param {number} id - The unique identifier for the article which is given by Intercom.
 * @param {Intercom.UpdateArticleRequest} request
 * @param {Articles.RequestOptions} requestOptions - Request-specific configuration.
 *
 * @throws {@link Intercom.UnauthorizedError}
 * @throws {@link Intercom.NotFoundError}
 *
 * @example
 *     await client.articles.update(1, {
 *         title: "Christmas is here!",
 *         body: "<p>New gifts in store for the jolly season</p>"
 *     })
 */
public async update(
    id: number,
    request?: Intercom.UpdateArticleRequest,
    requestOptions?: Articles.RequestOptions
): Promise<Intercom.Article> {
  ...
}

3. Improved exception handling

The SDK now defines structured errors that users can use to influence their program’s control flow. For example, consider the following:

import { Intercom } from "intercom-client";
try {
    await client.articles.update(...);
} catch (err) {
    if (err instanceof Intercom.NotFoundError) {
        // Do something with the 404 ...
    }
}

With this, users can write their programs to take specific actions whenever an endpoint returns any of the well-known Intercom errors (the Intercom.NotFoundError in this case).

4. Auto-pagination

Intercom’s paginated endpoints now support auto-pagination with an idiomatic iterator.

Callers don’t need to manually fetch the next page at all - they can simply iterate over the entire list, and the client will automatically fetch the next page behind the scenes.

Before

const response = client.companies.list({})
for (const company of response.data) {
  // Do something with the company …
}
if (response.pages.next != null) {
  // Fetch the next page, and keep iterating …
}

After

const page = client.companies.list()
for await (const company of page) {
  // Do something with the company …
}

5. Version selection

The Intercom client now includes version selection support.

The SDK is configured to use the latest stable version by default (i.e. 2.11), but users can override this value to influence the behavior of the server. Configuring a version is as simple as the following:

const client = new IntercomClient({ token, version: "2.11" });

Migration Guide

These improvements include a few breaking changes (primarily related to request parameters), which are categorized by the following:

1. Client constructor

The client constructor is simplified and doesn’t require a nested type to specify the API token.

Before

const client = new Client({
  tokenAuth: { token },
});

After

const client = new IntercomClient({ token });

2. Positional parameters

You’ll notice a few parameters are moved out of the in-lined request type and refactored as positional parameters.

Before

const response = client.contacts.listAttachedCompanies({
  id: "c89b0cd0-ab8a-43f0-8f03-4972427c446b"
})

After

const response = client.contacts.listAttachedCompanies(
  "c89b0cd0-ab8a-43f0-8f03-4972427c446b"
)

Note that additional optional parameters are still included in a separate in-lined request type like so:

Before

const response = client.contacts.listAttachedCompanies({
  id: "c89b0cd0-ab8a-43f0-8f03-4972427c446b"
  page: 1,
})

After

const response = client.contacts.listAttachedCompanies(
  "c89b0cd0-ab8a-43f0-8f03-4972427c446b",
  {
    page: 1
  }
)

2. Request properties naming convention (camelCase -> snake_case).

Request properties now use the snake_case naming convention, whereas response properties preserve the camelCase naming convention.

Before

const response = client.contacts.listAttachedCompanies({
  id: "c89b0cd0-ab8a-43f0-8f03-4972427c446b"
  perPage: 1,
})

After

const response = client.contacts.listAttachedCompanies(
  "c89b0cd0-ab8a-43f0-8f03-4972427c446b",
  {
    per_page: 1
  }
)
You must be logged in to vote

Replies: 6 comments · 9 replies

Comment options

@Eclairemoy — Wow, this is a huge update!

We're especially excited to see the robust typing and the auto-pagination.

On the pagination front, we had done some gymnastics to make something work using higher order functions, but it felt kludgy. I didn't know this type of looping is possible... This is a lot cleaner.

With our own internal services, we've found the type checking to help a lot across networking boundaries, as we've discovered too many errors when something changes over the wire.

Quick question... How does the typing interplay with the version selection? In other words, if different versions emit different data structures, does that mean that changing the version number (e.g. 1.0 vs 2.0 will cause the library to return different types?

Tiny API question... Since you're moving to positional parameters plus options hashes, would it make sense for IntercomClient to be initialized with the token as a first positional param?

Overall though, this looks like a big step up and it's great to see Intercom doubling down on the API front. It will make it easier for us to integrate it with our other systems as we adopt more AI-based support workflows.

You must be logged in to vote
1 reply
@amckinney
Comment options

Hey @brynary! I'm Alex, an engineer at Fern, who is responsible for Intercom's alpha release candidate. I'll go ahead and answer to your comments and questions in-line:

We're especially excited to see the robust typing and the auto-pagination.

On the pagination front, we had done some gymnastics to make something work using higher order functions, but it felt kludgy. I didn't know this type of looping is possible... This is a lot cleaner.

Great to hear that you're happy with the pagination solution! We took inspiration from what we've done in other SDK languages that we provide (like Python), and found that we could model it in the exact same way (i.e. as a simple iterator). We're also excited about the result!

Quick question... How does the typing interplay with the version selection? In other words, if different versions emit different data structures, does that mean that changing the version number (e.g. 1.0 vs 2.0 will cause the library to return different types?

The SDK typing will always be written in terms of the latest types. So in this case, the SDK is produced by 2.11. But the version header actually represents more than just the types you interact with - they sometimes alter the behavior of the server. For example, check out this section in 2.9’s CHANGELOG.md.

With that said, customizing the version header usually only makes sense when you need to leverage these behavioral changes. So no, changing the version number will not cause the library to return different types - only sometimes different values. This is inspired by Stripe's approach to versioning - each SDK has types are pinned to a particular version, but you are open to calling earlier version and ignoring the type guard rails.

Tiny API question... Since you're moving to positional parameters plus options hashes, would it make sense for IntercomClient to be initialized with the token as a first positional param?

We've considered this a bit. The current implementation is built towards consistency between client Options and RequestOptions. We have plans to support overriding the token on RequestOptions interface (along with every other Options property), so keeping the token defined as an option will end up with a similar UX across very call-site. For example,

const client = new IntercomClient(
  {
    token: "<token>"
  }
);

const response = client.companies.retrieve(
  {
    id: "…"
  },
  {
    token: "<token>"
  }
)

Overall though, this looks like a big step up and it's great to see Intercom doubling down on the API front. It will make it easier for us to integrate it with our other systems as we adopt more AI-based support workflows.

We're so happy to hear that! We appreciate all the thoughtful feedback, too. This is the best way to make the product even better 🎉

Comment options

I'm a founder and my company is currently a client of Intercom. We're on one of the paid plans. I just migrated to this new SDK release (took maybe 10 minutes) so here's my feedback.

Overall, it feels like this SDK update is much more modernized. The previous SDK wasn't even an ES module so I'm glad to get rid of the old import style. The type updates and new inline documentation were super helpful while migrating methods to the new format--I don't remember seeing that on previous versions. Other than that, not much changed for me. Just converted some camelCase arguments to underscore format and I was good to go.

Building an SDK is easy, but keeping it up-to-date is the hard part. The previous SDK felt like it was kinda neglected so hopefully Intercom can keep this quality up going forward.

I'm going to start using this in prod and will report back if anything unexpected comes up. Very happy with the update so far though!

You must be logged in to vote
1 reply
@Eclairemoy
Comment options

Eclairemoy Aug 1, 2024
Maintainer Author

Hey @joshuakcockrell - Thanks so much for this feedback. Happy to hear that the migration was easy and that it's been a positive experience so far. Feel free to share anything else that comes up along the way.

Comment options

We use Intercom here at Thera. We have to build integrations on a monthly basis, so seeing a Typescript client that has pagination with an iterator and declarative version selection is music to my ears. We're not going to start using this until it's promoted from alpha to a stable version.

@Eclairemoy, you have a timeline for that?

You must be logged in to vote
1 reply
@Eclairemoy
Comment options

Eclairemoy Aug 15, 2024
Maintainer Author

@reddyakhil Nothing confirmed yet, but we'll be sure to let you know when we do.

Comment options

I just tried beta3, and I encountered an issue that makes it somewhat troublesome to use. Why are all fields in each object defined as nullable/optional? When I retrieve a contact object, there are certain fields that are always to be present. However, because the type declaration makes all fields nullable, I have to add code to check these fields; otherwise, TypeScript throws an error.

You must be logged in to vote
4 replies
@Eclairemoy
Comment options

Eclairemoy Sep 2, 2024
Maintainer Author

Hi @nauxliu - please disregard the beta3 library as we won't be using it in the future. We recommend using the alpha version, let us know if you run into any issues with that one.

@nauxliu
Comment options

@Eclairemoy Ok, I thought beta was newer than alpha. Nevertheless, I switched to alpha. However, all fields on the contact form are still marked as optional.
image

@Eclairemoy
Comment options

Eclairemoy Sep 2, 2024
Maintainer Author

Ah I see. I think this may be an issue with our OpenAPI spec — I will look into it and update.

@nauxliu
Comment options

Hi @Eclairemoy, will there be a fix for this included in the 1st November release?

Comment options

Hello @Eclairemoy CTO credal.ai here, we're working on an Intercom integration but are not going to start until we can depend on the V6 Node SDK. When do you expect it to be released? This will be very helpful for our engineering planning and what we can push for our customers interested in intercom.

You must be logged in to vote
1 reply
@Eclairemoy
Comment options

Eclairemoy Oct 10, 2024
Maintainer Author

hey @jackfischer - The Typescript SDK will be available 1st November!

Comment options

Hi @Eclairemoy,
This new SDK looks very promising. I especially appreciate the addition of Types and Auto-pagination—great work! However, I’ve encountered an issue with Auto-pagination. It seems to work correctly for companies but not for collections.

Here’s an example that works as expected:

const page = client.companies.list()
for await (const company of page) {
  console.log(company.id);
}

But with collections, it doesn’t seem to work:

const page = client.helpCenter.collections.list()
for await (const collection of page) {
  console.log(collection.id);
}

I also tried a workaround by explicitly passing the page number and per_page parameter, but it seems to have no effect:

const page = client.helpCenter.collections.list({page: 2, per_page: 25});

Could you clarify the correct way to handle pagination for collections? Or is this a known issue?

Thanks in advance!

You must be logged in to vote
1 reply
@dsinghvi
Comment options

We're doing a v1 release next week -- we'll make sure that this is tested ahead of then!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
9 participants
Morty Proxy This is a proxified and sanitized view of the page, visit original site.