GithubHelp home page GithubHelp logo

intercom / intercom-node Goto Github PK

View Code? Open in Web Editor NEW
357.0 169.0 117.0 2.21 MB

Node.js bindings for the Intercom API

Home Page: https://developers.intercom.com

License: Other

TypeScript 100.00%
api intercom sdk

intercom-node's Introduction

intercom-node

Maintenance mode

The Intercom Node SDK is currently in maintenance mode whilst we consider the best way to support it. We are not currently accepting new feature requests or actively working on the SDK.

Circle CI npm Intercom API Version Typescript Supported

Official Node bindings to the Intercom API

Project Updates

Breaking changes

The Node SDK has been updated to support latest API version (2.6). The update also contains requested features, such like Typescript support. You can find more information on how-to migrate and what has changed in the migration guide.

Installation

yarn add intercom-client

This client is intended for server side use only. Please use the Intercom Javascript SDK for client-side operations.

Usage

Import Intercom:

import { Client } from 'intercom-client';

Create a client using access tokens:

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

Request Options

This client library also supports passing in request options:

const client = new Client({ tokenAuth: { token: 'my_token' } });
client.useRequestOpts({
    baseURL: 'http://local.test-server.com',
});

Note that certain request options (such as json, and certain headers names cannot be overriden).

Setting the API version

We version our API (see the "Choose Version" section of the API & Webhooks Reference for details). You can specify which version of the API to use when performing API requests using request options:

const client = new Client({ tokenAuth: { token: 'my_token' } });
client.useRequestOpts({
    headers: {
        'Intercom-Version': 2.6,
    },
});

Setting the API base url

If you are using the european instance of intercom and would like to call it directly and not be redirected through our US instance, you can set the baseUrl as follows:

const client = new Client({ tokenAuth: { token: 'my_token' } });
client.useRequestOpts({
    baseURL: 'https://api.eu.intercom.io',
});

Examples

Admins

const admin = await client.admins.find({ id: '123' });
await client.admins.away({
    adminId: '123',
    enableAwayMode: true,
    enableReassignMode: false,
});
await client.admins.listAllActivityLogs({
    before: new Date('Fri, 17 Dec 2021 18:02:18 GMT');,
    after: new Date('Fri, 17 Dec 2021 18:02:18 GMT');,
});
const admins = await client.admins.list();

Articles

const article = await client.articles.create({
    title: 'Thanks for everything',
    description: 'English description',
    body: '<p>This is the body in html</p>',
    authorId: 1,
    state: 'published',
    parentId: 1,
    parentType: 'collection',
    translatedContent: {
        fr: {
            title: 'Allez les verts',
            description: 'French description',
            body: '<p>French body in html</p>',
            author_id: 1,
            state: 'published',
        },
    },
});
const response = await client.articles.find({ id: '123' });
const article = await client.articles.update({
    id: '123',
    title: 'Thanks for everything',
    description: 'English description',
    body: '<p>This is the body in html</p>',
    authorId: 1,
    state: 'published',
    parentId: 1,
    parentType: 'collection',
    translatedContent: {
        fr: {
            title: 'Allez les verts',
            description: 'French description',
            body: '<p>French body in html</p>',
            author_id: 1,
            state: 'published',
        },
    },
});
await client.articles.delete({ id: '123' });
const response = await client.articles.list({
    page: 3,
    perPage: 12,
});

Companies

const company = await client.companies.create({
    createdAt: dateToUnixTimestamp(new Date()),
    companyId: '46029',
    name: 'BestCompanyInc.',
    monthlySpend: 9001,
    plan: '1. Get pizzaid',
    size: 62049,
    website: 'http://the-best.one',
    industry: 'The Best One',
    customAttributes: {},
});
const company = await client.companies.update({
    createdAt: dateToUnixTimestamp(new Date()),
    companyId: '46029',
    name: 'BestCompanyInc.',
    monthlySpend: 9001,
    plan: '1. Get pizzaid',
    size: 62049,
    website: 'http://the-best.one',
    industry: 'The Best One',
    customAttributes: {},
});
By id
const company = await client.companies.find({
    companyId: 123,
});
By name
const company = await client.companies.find({
    name: 'bruh moment inc.',
});
const company = await client.companies.delete({
    id: 62049,
});
With pagination
const companies = await client.companies.list({
    page: 1,
    perPage: 35,
    order: Order.DESC,
});
With TagId and SegmentId
const companies = await client.companies.list({
    tagId: '1234',
    segmentId: '4567',
});
Using infinite scroll
const companies = await client.companies.scroll.each({});
Using manual scroll
const companies = await client.companies.scroll.next({
    scrollParam: '123_soleil',
});
const response = await client.companies.attachContact({
    contactId: '123',
    companyId: '234',
});
const response = await client.companies.detachContact({
    contactId: '123',
    companyId: '234',
});
const response = await client.companies.listAttachedContacts({
    companyId: '123',
    page: 1,
    perPage: 15,
});
const response = await client.companies.listAttachedSegments({
    companyId: '123',
});

Contacts

With User Role
const user = await client.contacts.createUser({
    externalId: '536e564f316c83104c000020',
    phone: '+48370044567',
    name: 'Niko Bellic',
    avatar: 'https://nico-from-gta-iv.com/lets_go_bowling.jpg',
    signedUpAt: 1638203719,
    lastSeenAt: 1638203720,
    ownerId: '536e564f316c83104c000021',
    isUnsubscribedFromEmails: true,
});
With Lead Role
const lead = await client.contacts.createLead({
    phone: '+48370044567',
    name: 'Roman Bellic',
    avatar: 'https://nico-from-gta-iv.com/lets_go_bowling_yey.jpg',
    signedUpAt: 1638203719,
    lastSeenAt: 1638203720,
    ownerId: '536e564f316c83104c000021',
    isUnsubscribedFromEmails: true,
});
const response = await client.contacts.find({ id: '123' });
const response = await client.contacts.update({
    id: '123',
    role: Role.USER,
    name: 'Roman The Bowling Fan',
    customAttributes: {
        callBrother: "Hey Niko, it's me โ€“ Roman. Let's go bowling!",
    },
});
const response = await client.contacts.delete({ id: '123' });
const response = await client.contacts.archive({ id: '123' });
const response = await client.contacts.unarchive({ id: '123' });
const response = await client.contacts.mergeLeadInUser({
    leadId: '123',
    userId: '234',
});
const response = await client.contacts.search({
    data: {
        query: {
            operator: Operators.AND,
            value: [
                {
                    operator: Operators.AND,
                    value: [
                        {
                            field: 'updated_at',
                            operator: Operators.GREATER_THAN,
                            value: 1560436650,
                        },
                        {
                            field: 'conversation_rating.rating',
                            operator: Operators.EQUALS,
                            value: 1,
                        },
                    ],
                },
                {
                    operator: Operators.OR,
                    value: [
                        {
                            field: 'updated_at',
                            operator: Operators.GREATER_THAN,
                            value: 1560436650,
                        },
                        {
                            field: 'conversation_rating.rating',
                            operator: Operators.EQUALS,
                            value: 2,
                        },
                    ],
                },
            ],
        },
        pagination: {
            per_page: 5,
            starting_after:
                'WzE2MzU4NjA2NDgwMDAsIjYxODJiNjJlNDM4YjdhM2EwMWE4YWYxNSIsMl0=',
        },
        sort: { field: 'name', order: SearchContactOrderBy.ASC },
    },
});
With cursor
const response = await client.contacts.list({
    perPage: 5,
    startingAfter:
        'WzE2MzU3NzU4NjkwMDAsIjYxODJiNjJhMDMwZTk4OTBkZWU4NGM5YiIsMl0=',
});
Without a cursor
const response = await client.contacts.list();
const response = await client.contacts.listAttachedCompanies({
    id: '123',
    perPage: 5,
    page: 1,
});
const response = await client.contacts.listAttachedTags({ id: '123' });
const response = await client.contacts.listAttachedSegments({ id: '123' });
const response = await client.contacts.listAttachedEmailSubscriptions({
    id: '123',
});

Conversations

const response = await client.conversations.create({
    userId: '123',
    body: 'Hello darkness my old friend',
});
Formatted text
const response = await client.conversations.find({
    id: '123',
});
As plain text
const response = await client.conversations.find({
    id: '123',
    inPlainText: true,
});
const response = await client.conversations.update({
    id,
    markRead: true,
    customAttributes: {
        anything: 'you want',
    },
});
By id
As user
const response = await client.conversations.replyByIdAsUser({
    id: '098',
    body: 'blablbalba',
    intercomUserId: '123',
    attachmentUrls: '345',
});
As admin
const response = await client.conversations.replyByIdAsAdmin({
    id: '098',
    adminId: '458',
    messageType: ReplyToConversationMessageType.NOTE,
    body: '<b>Bee C</b>',
    attachmentUrls: ['https://site.org/bebra.jpg'],
});
By last conversation
As user
const response = await client.conversations.replyByLastAsUser({
    body: 'blablbalba',
    intercomUserId: '123',
    attachmentUrls: '345',
});
As admin
const response = await client.conversations.replyByLastAsAdmin({
    adminId: '458',
    messageType: ReplyToConversationMessageType.NOTE,
    body: '<b>Bee C</b>',
    attachmentUrls: ['https://site.org/bebra.jpg'],
});
As team without assignment rules
const response = await client.conversations.assign({
    id: '123',
    type: AssignToConversationUserType.TEAM,
    adminId: '456',
    assigneeId: '789',
    body: '<b>blablbalba</b>',
});
As team with assignment rules
const response = await client.conversations.assign({
    id: '123',
    withRunningAssignmentRules: true,
});
const response = await client.conversations.snooze({
    id: '123',
    adminId: '234',
    snoozedUntil: '1501512795',
});
const response = await client.conversations.close({
    id: '123',
    adminId: '456',
    body: "That's it...",
});
const response = await client.conversations.open({
    id: '123',
    adminId: '234',
});
As admin, using intercomUserid
const response = await client.conversations.attachContactAsAdmin({
    id: '123',
    adminId: '234',
    customer: {
        intercomUserId: '456',
    },
});
As contact, using intercomUserid
const response = await client.conversations.attachContactAsAdmin({
    id: '123',
    userId: '234',
    customer: {
        intercomUserId: '456',
    },
});
const response = await client.conversations.detachContactAsAdmin({
    conversationId: '123',
    contactId: '456',
    adminId: '789',
});
const response = await client.conversations.search({
    data: {
        query: {
            operator: Operators.AND,
            value: [
                {
                    operator: Operators.AND,
                    value: [
                        {
                            field: 'updated_at',
                            operator: Operators.GREATER_THAN,
                            value: 1560436650,
                        },
                        {
                            field: 'conversation_rating.rating',
                            operator: Operators.EQUALS,
                            value: 1,
                        },
                    ],
                },
                {
                    operator: Operators.OR,
                    value: [
                        {
                            field: 'updated_at',
                            operator: Operators.GREATER_THAN,
                            value: 1560436650,
                        },
                        {
                            field: 'conversation_rating.rating',
                            operator: Operators.EQUALS,
                            value: 2,
                        },
                    ],
                },
            ],
        },
        pagination: {
            per_page: 5,
            starting_after:
                'WzE2MzU4NjA2NDgwMDAsIjYxODJiNjJlNDM4YjdhM2EwMWE4YWYxNSIsMl0=',
        },
        sort: {
            field: 'name',
            order: SearchConversationOrderBy.DESC,
        },
    },
});
const response = await client.conversations.list({
    startingAfter: 'WzE2NzA0MjI1MjkwMDAsMjQzMTY3NzA2ODcsMl0=',
    perPage: 10,
});
const response = await client.conversations.redactConversationPart({
    type: RedactConversationPartType.CONVERSATION_PART,
    conversationId: '123',
    conversationPartId: '456',
});

Counts

const response = await client.counts.forApp();
const response = await client.counts.countConversation();
const response = await client.counts.countAdminConversation();
Count User Segment
const response = await client.counts.countUserSegment();
Count User Tag
const response = await client.counts.countUserTag();
Count Company Segment
const response = await client.counts.countCompanySegment();
const response = await client.counts.countCompanyTag();
const response = await client.counts.countCompanyUser();
Count Company Tag
const response = await client.counts.countCompanyTag();
Count Company User
const response = await client.counts.countCompanyUser();

Data Attributes

const response = await client.dataAttributes.create({
    name: 'list_cda',
    model: ModelType.CONTACT,
    dataType: DataType.STRING,
    description: 'You are either alive or dead',
    options: [{ value: 'alive' }, { value: 'dead' }],
});
const response = await client.dataAttributes.update({
    id: '123',
    description: 'You are either alive or dead',
    options: [{ value: 'alive' }, { value: 'dead' }],
    archived: true,
});
const response = await client.dataAttributes.list({
    model: ModelType.CONTACT,
    includeArchived: true,
});

Data Exports

const response = await client.dataExport.create({
    createdAtAfter: 1527811200,
    createdAtBefore: 1530316800,
});
const response = await client.dataExport.find({id: export.id})
const response = await client.dataExport.cancel({id: export.id})

Events

const response = await client.events.create({
    eventName: 'placed-order',
    createdAt: 1389913941,
    userId: 'f4ca124298',
    metadata: {
        order_date: 1392036272,
        stripe_invoice: 'inv_3434343434',
        order_number: {
            value: '3434-3434',
            url: 'https://example.org/orders/3434-3434',
        },
        price: {
            currency: 'usd',
            amount: 2999,
        },
    },
});
const response = await client.events.listBy({
    userId: '1234',
    perPage: 2,
    summary: true,
    email: '[email protected]',
});

Help Center - Collections

const collection = await client.helpCenter.collections.create({
    name: 'Thanks for everything',
    description: 'English description',
    translatedContent: {
        fr: {
            name: 'Allez les verts',
            description: 'French description',
        },
    },
});
const response = await client.helpCenter.collections.find({ id: '123' });
const article = await client.helpCenter.collections.update({
    id: '123',
    name: 'Thanks for everything',
    description: 'English description',
    translatedContent: {
        fr: {
            name: 'Allez les verts',
            description: 'French description',
        },
    },
});
await client.helpCenter.collections.delete({
    id: '123',
});
const response = client.helpCenter.collections.list({
    page: 3,
    perPage: 12,
});

Help Center - Sections

const collection = await client.helpCenter.sections.create({
    name: 'Thanks for everything',
    parentId: '1234',
    translatedContent: {
        fr: {
            name: 'Allez les verts',
            description: 'French description',
        },
    },
});
const response = await client.helpCenter.sections.find({ id: '123' });
const article = await client.helpCenter.sections.update({
    id: '123',
    name: 'Thanks for everything',
    parentId: '456',
    translatedContent: {
        fr: {
            name: 'Allez les verts',
            description: 'French description',
        },
    },
});
await client.helpCenter.sections.delete({
    id: '123',
});
const response = client.helpCenter.sections.list({
    page: 3,
    perPage: 12,
});

Messages

const response = await client.messages.create({
    messageType: 'email',
    subject: 'This is our demand now',
    body: 'Destroy ponies',
    template: 'plain',
    from: {
        type: 'admin',
        id: '394051',
    },
    to: {
        type: 'user',
        id: '536e564f316c83104c000020',
    },
});
const response = await client.messages.create({
    messageType: 'inapp',
    body: 'Look at me, I am a conversation now',
    from: {
        type: 'admin',
        id: '394051',
    },
    to: {
        type: 'user',
        id: '536e564f316c83104c000020',
    },
    createConversationWithoutContactReply: true,
});

Notes

const response = await client.notes.create({
    adminId: '12345',
    body: 'Shiny',
    contactId: '5678',
});
const response = await client.notes.find({ id: '123' });
const response = await client.notes.list({
    contactId: '123',
    page: 2,
    perPage: 3,
});

Segments

const response = await client.segments.find({
    id: '123',
    includeCount: true,
});
const response = await client.segments.list({
    includeCount: true,
});

Subscriptions

const response = await client.subscriptions.listTypes();

PhoneCallRedirects

const response = await client.phoneCallRedirect.create({
    phone: '+353871234567',
});

Tags

Create
const response = await client.tags.create({ name: 'haven' });
Update
const response = await client.tags.update({ id: '123', name: 'haven' });
const response = await client.tags.delete({ id: 'baz' });
const response = await client.tags.tagContact({
    contactId: '123',
    tagId: '234',
});
const response = await client.tags.tagConversation({
    conversationId: '123',
    tagId: '456',
    adminId: '789',
});
const response = await client.tags.tagCompanies({
    tagName: 'gutenTag',
    companiesIds: ['123', '234', '456'],
});
const response = await client.tags.untagCompanies({
    tagName: 'gutenTag',
    companiesIds: ['123', '234', '456'],
});
const response = await client.tags.untagConversation({
    conversationId: '123',
    tagId: '345',
    adminId: '678',
});
const response = await client.tags.untagContact({
    contactId: '123',
    tagId: '345',
});
const response = await client.tags.list();

Teams

const response = await client.teams.find({
    id: '123',
});
const response = await client.teams.list();

Visitors

const response = await client.visitors.find({ id: '123' });

OR

const response = await client.visitors.find({ userId: '123' });
const response = await client.visitors.update({
    userId: '123',
    name: 'anonymous bruh',
    customAttributes: {
        paid_subscriber: true,
    },
});
const response = await client.visitors.delete({
    id,
});
const response = await client.visitors.mergeToContact({
    visitor: {
        id: '123',
    },
    user: {
        userId: '123',
    },
    type: Role.USER,
});

Identity verification

intercom-node provides a helper for using identity verification:

import { IdentityVerification } from 'intercom-client';

IdentityVerification.userHash({
    secretKey: 's3cre7',
    identifier: '[email protected]',
});

License

Apache-2.0

Testing

yarn test

Running the code locally

Compile using babel:

yarn prepublish

Pull Requests

  • Add tests! Your patch won't be accepted if it doesn't have tests.

  • Document any change in behaviour. Make sure the README and any other relevant documentation are kept up-to-date.

  • Create topic branches. Don't ask us to pull from your master branch.

  • One pull request per feature. If you want to do more than one thing, send multiple pull requests.

  • Send coherent history. Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before sending them to us.

intercom-node's People

Contributors

apassant avatar bobjflong avatar choran avatar colinfkennedy avatar colmdoyle avatar danielhusar avatar dannyfallon avatar dependabot[bot] avatar em0ney avatar enrico-intercom avatar hypeofpipe avatar idris avatar irvinebroque avatar jakemaldonado avatar jeobrien avatar johnnynader avatar jonnyom avatar khalilovcmd avatar louisremi avatar mattdonnelly avatar mckenna avatar mmartinic avatar pizza avatar punkle avatar rhodgkins avatar ruairik avatar seanhealy33 avatar suma-prakash avatar tejasmanohar avatar thibaultdalban avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

intercom-node's Issues

api rate limit

One of the problems when using the unofficial node lib (not the lib's fault) is the strict api rate limit. There's a limit of ~500 user updates per minute which is very low if you want to bulk update users.

Does this lib handles this limitation in any way?

Revise Promise support

I would recommend copying Stripe's approach to supporting Promises rather than the current usePromises() approach. Typically, you would just have it return a promise unless there's a callback passed in. You also can use Bluebird's nodeify function or just a separate node module to handle this for you- https://www.npmjs.com/package/nodeify- and just stick to Promises in the core- wouldn't recommend anything different tbh.

It's also acceptable to just expose Promises and let the developer using the module nodeify it / wrap it if they prefer callbacks, imo (same with callbacks, just that Promises are the way things are headed towards).

Thoughts? @bobjflong

Add additional properties to the Error object (in particular statusCode`

Currently the only way to get the actual error message, code etc. is to parse error.message

In my case I first check to see if a user with a given email exists - If not I create them as a lead. Checking if a user exists throws a 404, so I need to JSON.parse(err.message) to see if its just a 404, or some other error.

It would be nice if I could just check error.code / error.statusCode

Version info

  • intercom-node version: 2.8.0
  • Node version: any

Expected behavior

error.code or similar is defined

Actual behavior

error.message is the only property - I have to JSON.parse it to get the statusCode

Steps to reproduce

  1. Search for a non-existent user
  2. Catch the error

Readme incorrectly cites users.update method

There is no client.users.update method--only client.users.create. The readme incorrectly lists the former, whereas one must actually use the latter, which has UPSERT behavior, to update OR create the user.

Bad babel dependency

Can you guys please update your "babel-core" dependency from 5.5 to version 6. This has a fix for an unpublished dependency thank you.

usePromise throws error on list

intercom-node 2.6
node 5.5

I am trying to fetch a list of my conversations, but when I use usePromises it throws an error. If I use it with callbacks, it works as expected.

Update: Turns out you need to pass an empty object instead of undefined if you want to fetch all. I would add this to the docs or default the query to {} if null/undefined.

const Intercom = require('intercom-client');
const INTERCOM_API_KEY = process.env.INTERCOM_PRODUCTION_RO_API_KEY;
const INTERCOM_APP_ID = process.env.INTERCOM_PRODUCTION_APP_ID;

const client = new Intercom.Client(INTERCOM_APP_ID, INTERCOM_API_KEY)
  .usePromises();

client.conversations.list()
  .then((res) => {
    console.log(res);
  });
kel@Wombat:~/Projects/intercom-explorer (master #)$ node index.js
/Users/kel/Projects/intercom-explorer/node_modules/unirest/index.js:214
        if (!value.length) return $this;
                  ^

TypeError: Cannot read property 'length' of undefined
    at Object.$this.query (/Users/kel/Projects/intercom-explorer/node_modules/unirest/index.js:214:19)
    at Client.get (/Users/kel/Projects/intercom-explorer/node_modules/intercom-client/dist/client.js:155:144)
    at Conversation.list (/Users/kel/Projects/intercom-explorer/node_modules/intercom-client/dist/conversation.js:21:26)
    at Object.<anonymous> (/Users/kel/Projects/intercom-explorer/index.js:8:22)
    at Module._compile (module.js:413:34)
    at Object.Module._extensions..js (module.js:422:10)
    at Module.load (module.js:357:32)
    at Function.Module._load (module.js:314:12)
    at Function.Module.runMain (module.js:447:10)
    at startup (node.js:139:18)
    at node.js:999:3

User Agent Data not showing in Intercom

Hi,

I'm creating leads through a form on my site using this library. In addition to email and IP Address, I'm passing along the User Agent string pulled directly from the request headers. Unfortunately, this information isn't showing up in the lead's profile.

Here's my code:

intercomClient.contacts
            .create({
              email: userEmail,
              last_seen_ip: userIpAddress,
              user_agent_data: request.headers['user-agent']
            })
            .then(() => {
              return reply();
            })
            .catch((err) => {
              return reply(Boom.badImplementation(err));
            });

Here's the string coming from the headers:

Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.86 Safari/537.36

And here's what I'm seeing in Intercom:

image

I thought it might be a format issue, but I tried the data in the CURL Example, but no luck.

Thanks!

Add error messages

Found two uses

Invalid use that responded with an empty response instead of something like "Error: 'message_type' must be 'email' or 'inapp'"

var Intercom = require('intercom-client')
var client = new Intercom.Client('foo', 'bar').usePromises()

var message = {
  message_type: 'message', // this is an invalid type
  body: 'Hi this is a admin initiated message',
  from: {
      type: 'admin',
      id: '123'
    },
  to: {
      type: 'user',
      id: '123'
    }
}

client.messages.create(message).then(console.log)
// => no response

Resource not found responds with an empty response instead of something like "Error: user not found"

var Intercom = require('intercom-client')
var client = new Intercom.Client('foo', 'bar').usePromises()

var message = {
  message_type: 'inapp', 
  body: 'Hi this is a admin initiated message',
  from: {
      type: 'admin',
      id: '123'
    },
  to: {
      type: 'user',
      id: '123' // not a real user
    }
}

client.messages.create(message).then(console.log)
// => no response

I can understand if you'd prefer to fail silently for the second issue (though it would be nice if there was a setting to make it throw an error) but I def think the first one should have an error - required key having an invalid value

user.update?

I want to set some custom attributes on some existing users. Looking at the doc here updating a user is supported

https://doc.intercom.io/api/#create-or-update-user

The api doesn't have an update call but but does have the create/post. What are best practices for updating. Is it to call create again on the user?

My plan was to

Find user
Update the custom attributes object
update user (call create on existing user object with updated custom attributes?)

Change the User documentation/code to take user_id as an argument, rather than ID, as well as adding email.

Firstly, thanks for writing a sweet API!
Secondly, the following code would be very useful and not difficult to implement:

//Find user by id
client.users.find({ id: '1234' }, callback);

would be better represented as:

//Find user by id
(client.users.find({ user_id: '1234' }, callback);

as this would be less misleading. This would not be a difficult fix either and would be much more practical to use.

As well as the above issue, the following would be extremely useful:

// Find user by email
client.users.find({ email: '[email protected]' }, callback);

It could be implemented in user.js using:

client.get('/users/?email=${email}', {}, callback);

Cheers!

Cannot find module "fs" error along with multiple other errors with webpack dev server

Please use the following template to submit your issue. Following this template will allow us to quickly investigate and help you with your issue. Please be aware that issues which do not conform to this template may be closed.

For feature requests please contact us at [email protected]

Version info

  • intercom-node version: 2.8.5
  • Node version: 6.8.1

Expected behavior

Actual behavior

Steps to reproduce

  1. when ever i require var Intercom = require('intercom-client')
  2. the errors show up in console

Logs

Uncaught Error: Cannot find module "fs"
    at webpackMissingModule (form_data.js:7)
    at Object.<anonymous> (form_data.js:7)
    at Object.<anonymous> (form_data.js:353)
    at __webpack_require__ (bootstrap 68e893cโ€ฆ:585)
    at fn (bootstrap 68e893cโ€ฆ:109)
    at Object.<anonymous> (index.js:15)
    at Object.<anonymous> (index.js:1091)
    at __webpack_require__ (bootstrap 68e893cโ€ฆ:585)
    at fn (bootstrap 68e893cโ€ฆ:109)

./~/unirest/index.js
./~/mime/mime.js
./~/mime/types.json
/~/unirest/~/form-data/lib/form_data.js
./~/unirest/~/mime-db/db.json
./~/tough-cookie/package.json
./~/request/lib/har.js...

Instantiate new client with a credentials object?

new Intercom.Client({
    apiKey: 'apiKey',
    appId: 'appId'
}

is generally less error-prone and more readable than

new Intercom.Client('app_id', 'api_key');

Not super critical, but easier to change while there are not too many users.

Reply to api initiated conversation not working

Version info

  • intercom-node version: 2.8.6
  • Node version: 4.3.1

Expected behavior

After creating and admin or user initiated conversation it would be great to reply to it.

Actual behavior

After creating the admin or user initiated conversation if you try to reply to it providing the conversation id, it's not working.

  • The id of the conversation does not match the id that I can see in the messages inbox... so it looks like the conversation id is not provided...!

Steps to reproduce

  1. Create an admin or user initiated conversation
  2. Reply to it providing the id from last request

Logs

body.errors [{"code":"not_found","message":"Resource Not Found"}]

Workaround

I found that I can pass id: 'last' and it works but it's more an hack...! (Library code enabling that and doc for last reply)

AppId still required

Documentation states I can use the token alone:
var client = new Intercom.Client({ token: 'my_token' });

But I still needed to pass the AppId:
var client = new Intercom.Client({ appId: 'my_appId', token: 'my_token' });

Secure Mode

I see that there exist user_hash method, but i don't now, in which request i should put it(hash). For example, if i am trying to create user with user hash, calculated using your method(user_id as argument), response is:

errors: [ { "code": "bad_request', message: 'bad \"user_hash\" parameter"} ]

My request payload:

{
    "user_id": "12345677",
    "email": "[email protected]",
    "user_hash": "calculatedHash"
}

[Feature Request] add user hash utility

It would be helpful to have a function like this:

var client = new Intercom.Client({secretKey: MY_SECRET});
var userHash = client.userHash(userId);
// or
var userHash = Intercom.Util.generateUserHash({secretKey: MY_SECRET, userId: userId});

I know it just does this:

var crypto = require('crypto');
var userHash = crypto.createHmac('sha256', MY_SECRET).update(userId.toString()).digest('hex');

but it would be helpful to not learn that.

This request comes from enabling secure mode: https://docs.intercom.io/configuring-Intercom/enable-secure-mode.

I'm a bit confused if you prefer snake or camel casing.

Thanks.

Multiple existing users match this email address Error

i have a segment like the following code snippet which finds a user by their email and sends an intercom message using the api. the issue is sometimes i get an error like the following.

{"statusCode":400,"body":{"type":"error.list","request_id":"almvmvb7hnr3hjonq670","errors":[{"code":"conflict","message":"Multiple existing users match this email address [email protected] - must be more specific using user_id"}]}

I'm pretty sure this is because this email exists twice in intercom, since we were, for a while, using the same intercom app for both our dev and prod ios apps.

so my first question is in this case it possible to return a list of users , maybe using listBy instead of just throwing an error when this case happens?

    client.users.find({ email: req.user.email })
     .then(function (r) {
      var message = {
        message_type: 'inapp',
        subject: subject,
        body: msg,
        template: 'plain',
        from: {
          type: 'admin',
          id: process.env.INTERCOM_FROM_ACCOUNT,
        },
        to: {
          type: 'user',
          user_id: r.body.user_id,
        },
      };
      return client.messages.create(message);
    }).then(function (r) {
      return res.status(200).json({ success: true, message: helper.strings.MessageSent });
    }).catch(function (e) {
      helper.logging.logError(e, req);
      res.status(500).json({ success: false, message: helper.strings.AnErrorHappened });
    });

secondly, this might be more an iOS question, but I dont even see a way to get the user id from the API to pass it to the server.

Anyways, any suggestions are appreciated.

non standard error handling in callbacks

According to the lib's docs Callbacks section:

This client library supports two kinds of callbacks:

// Option #1
client.users.list(function (d) {
  // d is the response from the server
});

// Option #2
client.users.list(function (err, d) {
  // err is an error response object, or null
  // d is a successful response object, or null
});

How does Intercom know which style you want ? It checks the amount of arguments in your callback function and sends you each time a different one accordingly.

This is very confusing and non standard:

  1. In Node world an error object should always return first and results second.
  2. Adds unnecessary "magic" to the callback function. The results you get are determined by the amount of arguments you passed. Not a good thing.
  3. This approach favors response data over response error. In reality, you should check for response error 100% of the times. But checking response data is not always necessary (from my personal experience with Intercom's service, it's usually not necessary)

Internal node error when sending a message

I've encountered a strange error when using the library to send messages. I'll do my best to describe the issue, but my use case is quite particular.

I am using node's cluster module and the Intercom message is being sent via a child process and is also wrapped inside a try/catch block to ensure no uncaught errors cause the child process to crash. The Intercom message was the last call in the async chain, but it appears that it was never able to successfully call its callback as this internal node error appears in the logs:

nodejs: ../src/util-inl.h:196: TypeName* node::Unwrap(v8::Local<v8::Object>) [with TypeName = node::crypto::SecureContext]: Assertion `(object->InternalFieldCount()) > (0)' failed.

Logging the exit code and signal of the forked process (via the master process' on.("exit", ...) event) shows that it exits with code null and signal SIGABRT.

Removing the Intercom message method stops the internal node error from appearing, the final callback is called, and the process exits with no errors. For now, I have replaced the library with a simple HTTP request via the request library and everything works correctly.

For reference, this was running on Ubuntu 14.04, Docker 1.10.2, Node v4.3.0.

I apologize if any of this is vague. Please ask for whatever details you may in order to look into this and I'll be happy to clarify.

Using Access token in client app safe?

intercom docs state "Personal Access Tokens should never be shared outside of your company" . I am integrating intercom in a React SPA, thus was concerned if its safe to disclose access token on client side.

Can't find company using company_id attribute.

Version info

  • intercom-node version: 2.8.5^
  • Node version: v6.9.2

Expected behavior

My app's company_id type is Number, and I want to find user list in specific company(ex: company_id: 100).
I call to the listUsers API, but get the error.
I expect can do it using company_id, but intercom-node module doesn't implement it.

Intercom developer ref: List company users

Actual behavior

Unhandled rejection Error

Steps to reproduce

companies.listUsers({id: '100'}).then(r => {
      console.log(r);
    });
or
companies.find({id: '100'}).then(r => {
      console.log(r);
});

Logs

Unhandled rejection Error: {"statusCode":404,"body":{"type":"error.list","request_id":"apr7l9f98ocvgbpv7dq0","errors":[{"code":"not_found","message":"Company Not Found"}]},"headers":{"cache-control":"no-cache","content-type":"application/json; charset=utf-8","date":"Thu, 26 Jan 2017 08:35:47 GMT","server":"nginx",
"set-cookie":["_mkra_ctxt=9de3915db548df5a585796b1497cab2a--404; path=/; max-age=5; HttpOnly; secure"],"status":"404 Not Found","strict-transport-security":"max-age=31557600; includeSubDomains; preload","vary":"Accept-Encoding",
"x-content-type-options":"nosniff","x-frame-options":"SAMEORIGIN","x-intercom-version":"7b241962ebd2722082d2c21c7c8dae7de99ff8e2","x-request-id":"apr7l9f98ocvgbpv7dq0","x-runtime":"0.054100","x-xss-protection":"1; mode=block","transfer-encoding":"chunked","connection":"Close"},
"request":{"uri":{"protocol":"https:","slashes":true,"auth":null,"host":"api.intercom.io","port":443,"hostname":"api.intercom.io","hash":null,"search":null,"query":null,"pathname":"/companies/279","path":"/companies/279","href":"https://api.intercom.io/companies/279"},
"method":"get","headers":{"Content-Type":"application/json","Accept":"application/json","User-Agent":"intercom-node-client/2.0.0","authorization":"Basic ZEc5ck9qUmtNak0xWVRVMFh6WmtZMkZmTkdWak5WODVNR0pqWHpnNVpUTmpOV0U0TVRrME9Ub3hPakE9Og==","content-length":0}}}

If you have a plan that find data using company_id, I can make P/R.
maybe

listUsers(params, f) {
    if (params.company_id !== undefined) {
      return this.client.get(`/companies`, {company_id: params.company_id, type: 'user'}, f);
    } else (
      return this.client.get(`/companies/${params.id}/users`, {}, f);
    }
}

Thank you.

No error handling

Version info

  • intercom-node version: 2.8.5
  • Node version: 7.x

Expected behavior

When making an invalid call, throw an error or call callback with error

Actual behavior

Silence

Steps to reproduce

  1. intercom.users.find({ some_attribute_other_than_id_or_email_or_user_id: 123 })

Remove arity detection

This isn't a bug - more a suggested deprecation.

You're currently using arity detection to decide on the behavior for callbacks. This is consistently considered bad practice in JS. I did bring it up in the PR where it was introduced (#18 (comment)) but received no response.

This is particularly problematic in Node, where this is considered standard/idiomatic:

intercom.users.list(error => {
    if (error)
        log.warn('blah', [error]);
});

Executing the code above would result in unexpected behavior. It could be resolved by adding an unused second parameter to the function, but most linters consider this an error:

I'd suggest deprecating this behavior and then removing it in a future v3.

Bulk user creation has wrong Accept header

Version info

  • intercom-node version: 2.7.0
  • Node version: 5.9.1

Expected behavior

Create users in bulk

Actual behavior

Returns an error list containing an error of type: media_type_not_acceptable

Steps to reproduce

  1. Set up client
  2. Build array of users to add
  3. Set up request
  4. Inspect error.list

Client:

'use strict';

var IntercomAPI = require( 'intercom-client' );

module.exports = new IntercomAPI.Client( {
    appId     : process.env.INTERCOM_APP_ID,
    appApiKey : process.env.INTERCOM_APP_ID_KEY
} )
    .usePromises();

Request:

var client = require( './client.js' );

module.exports = function( members ) {

    var users = [];

    for ( var key in members ) {
        members.hasOwnProperty( key ) && users.push( {
            create : members[ key ]
        } );
    }

    return client.users.bulk( users )
        .then( function( response ) {
            console.info( '[intercom] [INFO] [Users: Add response]',
                JSON.stringify( response )
            );
        } );
}

Logs

Result of the error list:

{
    "errors": [
        {
            "code": "media_type_not_acceptable",
            "message": "The Accept header should send a media type of application/json"
        }
    ],
    "type": "error.list"
}

URGENT: "remote_created_at" on users.create started breaking 07:37 PST

Important: Would be great if this can be fixed ASAP.
We are about to start loosing data here in the next 12 hours.

This might be an issue with the API and this client using deprecated functionality?

Version info

  • intercom-node version: 2.8.5
  • Node version: v4.3.2

Expected behavior

Can create user with "signed_up_at" value.

Actual behavior

Receive error message saying bad 'remote_created_at' parameter.

Minimal Test Case

const Intercom = require('intercom-client');

const INTERCOM_APP_ID = "xxxxxx";
const INTERCOM_API_KEY = "*******************";

var client = new Intercom.Client(INTERCOM_APP_ID, INTERCOM_API_KEY);

client.users.create({
  "signed_up_at": "2016-11-24T02:51:26.363097+00:00",
  "user_id": "12345675c235883a4f0c877a32fc9dd8"
}, function (resp) {
  console.log(resp.status);
  console.log(JSON.stringify(resp.body, null, 4));
});

Error Response (400)

{
    "type": "error.list",
    "request_id": null,
    "errors": [
        {
            "code": "bad_request",
            "message": "bad 'remote_created_at' parameter"
        }
    ]
}

Implement Scroll API

As far as I can tell, the scroll API isn't implemented?
Are there plans to implement this? I'm having to paginate through all users and I'm hitting the page limit.

Can't this be used on the browser getting the error

Please use the following template to submit your issue. Following this template will allow us to quickly investigate and help you with your issue. Please be aware that issues which do not conform to this template may be closed.

For feature requests please contact us at [email protected]

Version info

  • intercom-node version:
  • Node version: v4.4.5

Not able to use with browserify and backbone.js .. Following error comes

XMLHttpRequest cannot load https://api.intercom.io/users. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. The response had HTTP status code 406.

client.contacts.create throws an error if second arg is not defined

The main reason I am submitting this is because the method actually succeeds in creating the contact, but throws an error in the application.

Instead of me having to write an empty callback create(userData, function (r) {}) to avoid the error.
I would prefer being able to simply leave it off create(userData)

screen shot 2015-10-02 at 8 48 43 am

Node-style callbacks?

Hi team,

I've been looking at switching to the official client from this unoffical one.

The two main problems:

  • MUST HAVE: The callback are not standard node-style callbacks (e.g. function(err, result)). One advantage of the unoffical intercom.io was to reject the promise (or return an err in the callback) when the response body would contain an error. In my opinion, this is one of the main advantages of using a node wrapper vs. the standard API.
  • SHOULD HAVE: Support for promises (in addition to callbacks) would be really great (especially since this seems to be a feature of ES6)

Sticking to the other library in the meantime!

Always getting http satus 401

I am trying to get users from Intercom .
code:

var client = new Intercom.Client(appId,apiKey);
client.users.create({ email: '[email protected]' }, function (response) {
      console.log(response);
    });

I am using api key and Id which have Read & Write access.
But we are getting back https status 401

 {"type":"error.list","request_id":"aacda07a-b315-4a58-a800-046efb118dbb","errors":[{"code":"token_not_found","message":"Unauthorized 
"}]}].

Please help.:)
Thanks

[question] Is documented which type of email templates are available?

I did not find a list of possible values to use for the template property nor a route which would allow me to query this.

My use case is, that I want to send an email with a certain style/template applied. From the intercom web app these 4 should be possible (plain, company, personal, announcement). Applying any of these strings as a param resulted in the same email sent.

Version info

  • intercom-node version: 2.8.5
  • Node version: 7.1.0

Expected behavior

The provided template is used for the email.

Actual behavior

It always uses the personal template

Steps to reproduce

//Require Intercom
var Intercom = require('intercom-client');
var client = new Intercom.Client({ token: token });

// Admin initiated messages:
// Sending an email to a User
var message = {
  message_type: "email",
  subject: "Hey",
  body: "Simple email from intercom",
  template: "company",
  from: {
    type: "user",
    user_id: "582b18f6c370b6344a52b076"
  },
  to: {
    type: "user",
    user_id: "5825c98f1be52a4141905907"
  }
}

client.messages.create(message).then(function (data) {
  console.log('data: ', data.body)
})

Logs

data: { type: 'user_message',
  id: '59464454',
  created_at: 1479224902,
  body: 'Simple email from intercom',
  message_type: 'inapp' }

How to get user events?

Version info

  • intercom-node version: 2.8.0
  • Node version:

Expected behavior

Calling intercom.users.find({ user_id: userId }) returns events in body.events in the same way as it does for body.custom_attributes.

Actual behavior

No events are in the response anywhere I can see them.

404 error when i was calling message.create method .

Hi , I was getting below error when i was calling messages.create method .

Can any one explore this

"body": { "type": "error.list", "request_id": "alnvbrgmmvv77ttsm17g", "errors": [ { "code": "not_found", "message": "Resource Not Found" } ] },

listing by page

When you call user.list() it suggests that it only returns the first n items (along with a pages object to show how many other pages there are). As far as I can see though there is no way to get any other page from the api other than the first. Is there any way to list all users or get the users on the next n pages?

https://doc.intercom.io/api/#list-users

Events with 'user_id'

Hi,

Is there any reason that events could not be sent using a user_id?
Since email are not a unique key, it could be confusing to send an event if two emails are the same.

Moreover, I don't understand this doc section:

// Note: events will work when identified by 'email'.

// Create a event
client.events.create({
  event_name: 'Foo',
  created_at: 1439826340,
  user_id: 'bar'
}, function (d) {
  console.log(d);
});

Do you mean it will only work with the email field?

Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.