Giter Site home page Giter Site logo

hubspot-api-nodejs's Introduction

hubspot-api-nodejs

NodeJS v3 HubSpot API SDK(Client) files

Sample apps

Please, take a look at our Sample apps

Available SDK methods reference

Available SDK methods reference

Installing

npm install @hubspot/api-client

Instantiate client

const hubspot = require('@hubspot/api-client')
const hubspotClient = new hubspot.Client({ accessToken: YOUR_ACCESS_TOKEN })

Note

Please note that all code examples are written in JavaScript. Some of them won’t work in Typescript without changes.

For ES modules

import { Client } from "@hubspot/api-client";
const hubspotClient = new Client({ accessToken: YOUR_ACCESS_TOKEN });

You'll need to create a private app to get your access token or you can obtain OAuth2 access token.

You can provide developer API key. There is no need to create separate client instances for using endpoints with API key and Developer API key support.

const hubspotClient = new hubspot.Client({ developerApiKey: YOUR_DEVELOPER_API_KEY })
const hubspotClient = new hubspot.Client({ accessToken: YOUR_ACCESS_TOKEN, developerApiKey: YOUR_DEVELOPER_API_KEY })

To change the base path:

const hubspotClient = new hubspot.Client({ accessToken: YOUR_ACCESS_TOKEN, basePath: 'https://some-url' })

To add custom headers to all request:

const hubspotClient = new hubspot.Client({
    accessToken: YOUR_ACCESS_TOKEN,
    defaultHeaders: { 'My-header': 'test-example' },
})

If you're an app developer, you can also instantiate a client and obtain a new accessToken with your app details and a refresh_token:

hubspotClient.oauth.tokensApi
    .create('refresh_token', undefined, undefined, YOUR_CLIENT_ID, YOUR_CLIENT_SECRET, YOUR_REFRESH_TOKEN)
    .then((results) => {
        console.log(results)

        // this assigns the accessToken to the client, so your client is ready
        // to use
        hubspotClient.setAccessToken(results.accessToken)

        return hubspotClient.crm.companies.basicApi.getPage()
    })

Rate limiting

Bottleneck is used for rate limiting. To turn on/off rate limiting use limiterOptions option on Client instance creation. Bottleneck options can be found here. Please note that Apps using OAuth are only subject to a limit of 100 requests every 10 seconds. Limits related to the API Add-on don't apply.

const hubspotClient = new hubspot.Client({
    accessToken: YOUR_ACCESS_TOKEN,
    limiterOptions: DEFAULT_LIMITER_OPTIONS,
})

Default settings for the limiter are:

const DEFAULT_LIMITER_OPTIONS = {
    minTime: 1000 / 9,
    maxConcurrent: 6,
    id: 'hubspot-client-limiter',
}

Search settings for the limiter are:

const SEARCH_LIMITER_OPTIONS = {
    minTime: 550,
    maxConcurrent: 3,
    id: 'search-hubspot-client-limiter',
}

Retry mechanism

It's possible to turn on retry for failed requests with statuses 429 or 5xx. To turn on/off configurable retries use numberOfApiCallRetries option on Client instance creation. numberOfApiCallRetries can be set to a number from 0 - 6. If numberOfApiCallRetries is set to a number greater than 0 it means that if any API Call receives ISE5xx this call will be retried after a delay 200 * retryNumber ms and if 429 (Rate limit is exceeded) is returned for "TEN_SECONDLY_ROLLING" the call will be retried after a delay 10 sec. Number of retries will not exceed numberOfApiCallRetries value.

const hubspotClient = new hubspot.Client({
    accessToken: YOUR_ACCESS_TOKEN,
    numberOfApiCallRetries: 3,
})

Usage

All methods return a promise. The success includes the serialized to JSON body and response objects. Use the API method via:

hubspotClient.crm.contacts.basicApi
    .getPage(limit, after, properties, propertiesWithHistory, associations, archived)
    .then((results) => {
        console.log(results)
    })
    .catch((err) => {
        console.error(err)
    })

{EXAMPLE} Create Contact, Company and associate created objects

const contactObj = {
    properties: {
        firstname: yourValue,
        lastname: yourValue,
    },
}
const companyObj = {
    properties: {
        domain: yourValue,
        name: yourValue,
    },
}

const createContactResponse = await hubspotClient.crm.contacts.basicApi.create(contactObj)
const createCompanyResponse = await hubspotClient.crm.companies.basicApi.create(companyObj)
await hubspotClient.crm.associations.v4.basicApi.create(
    'companies',
    createCompanyResponse.id,
    'contacts',
    createContactResponse.id,
    [
        {
              "associationCategory": "HUBSPOT_DEFINED",
              "associationTypeId": AssociationTypes.companyToContact
              // AssociationTypes contains the most popular HubSpot defined association types
        }
    ]
)

{EXAMPLE} Get associated Companies by Contact

const companies = await hubspotClient.crm.associations.v4.basicApi.getPage(
    'contact',
    hubspotContactId,
    'company',
    after,
    pageSize,
  );

{EXAMPLE} Update multiple objects in batch mode

const dealObj = {
    id: yourId,
    properties: {
        amount: yourValue,
    },
}

const dealObj2 = {
    id: yourId,
    properties: {
        amount: yourValue,
    },
}

await hubspotClient.crm.deals.batchApi.update({ inputs: [dealObj, dealObj2] })

{EXAMPLE} Import Contacts

const fs = require('fs')

const fileName = 'test.csv'

const file = {
    data: fs.createReadStream(fileName),
    name: fileName,
};

const importRequest = {
    name: 'import(' + fileName + ')',
    files: [
        {
            fileName: fileName,
            fileImportPage: {
                hasHeader: true,
                columnMappings: [
                    {
                        columnName: 'First Name',
                        propertyName: 'firstname',
                        columnObjectType: 'CONTACT',
                    },
                    {
                        columnName: 'Email',
                        propertyName: 'email',
                        columnObjectType: 'CONTACT',
                    },
                ],
            },
        },
    ],
}

const response = await  hubspotClient.crm.imports.coreApi.create(file, JSON.stringify(importRequest));

console.log(response)

{EXAMPLE} Search Contacts

Only 3 FilterGroups with max 3 Filters are supported.

Despite sorts is an array, however, currently, only one sort parameter is supported.

In JS sorts it's possible to set as:

  1. < propertyName > - returned results will be sorted by provided property name in 'ASCENDING' order. e.g: `'hs_object_id'``
  2. < direction > - returned results will be sorted by provided property name and sort direction. e.g: { propertyName: 'hs_object_id', direction: 'ASCENDING' } or { propertyName: 'hs_object_id', direction: 'DESCENDING' }

In TS sorts it's possible to set as:

  1. < propertyName > - returned results will be sorted by provided property name in 'ASCENDING' order. e.g: ['hs_object_id']
  2. < direction > - use ["-createdate"] to sort in desc and sorts: ["createdate"] in asc order.

after for initial search should be set as 0

Example for JS:

const publicObjectSearchRequest = {
    filterGroups: [
    {
        filters: [
        {
            propertyName: 'createdate',
            operator: 'GTE',
            value: `${Date.now() - 30 * 60000}`
        }
        ]
    }
    ],
    sorts: [{ propertyName: 'createdate', direction: 'DESCENDING' }],
    properties: ['createdate', 'firstname', 'lastname'],
    limit: 100,
    after: 0,
}

const response = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest)

console.log(response)

Example for TS:

const objectSearchRequest: PublicObjectSearchRequest = {
    filterGroups: [
        {
            filters: [
                {
                propertyName: "createdate",
                operator: "GTE",
                value: "1615709177000",
                },
            ],
        },
    ],
    sorts: ["-createdate"],
    properties: ["email", "createdate"],
    limit: 100,
    after: '0',
};

const response = await hubspotClient.crm.contacts.searchApi.doSearch(objectSearchRequest);

console.log(response)

Get all

getAll method is available for all major objects (Companies, Contacts, Deals, LineItems, Products, Quotes & Tickets) and works like

const allContacts = await hubspotClient.crm.contacts.getAll()

Note

Please note that pagination is used under the hood to get all results.

Upload a file (via the SDK)

const response = await hubspotClient.files.filesApi.upload(
    {
        data: fs.createReadStream('./photo.jpg'),
        name: 'photo.jpg'
    },
    undefined,
    '/folder',
    'photo.jpg',
    undefined,
    JSON.stringify({
        access: 'PRIVATE',
        overwrite: false,
        duplicateValidationStrategy: 'NONE',
        duplicateValidationScope: 'ENTIRE_PORTAL',
    })
)

console.log(response)

OAuth

Obtain your authorization url

const clientId = 'your_client_id'
const redirectUri = 'take_me_to_the_ballpark'
const scope = 'some scopes'
const uri = hubspotClient.oauth.getAuthorizationUrl(clientId, redirectUri, scope)

Obtain an access token from an authorization_code

return hubspotClient.oauth.tokensApi.create(
        'authorization_code',
        code, // the code you received from the oauth flow
        YOUR_REDIRECT_URI,
        YOUR_CLIENT_ID,
        YOUR_CLIENT_SECRET,
    ).then(...)

CMS

Get audit logs

const response = await hubspotClient.cms.auditLogs.auditLogsApi.getPage()

Not wrapped endpoint(s)

It is possible to access the hubspot request method directly, it could be handy if client doesn't have implementation for some endpoint yet. Exposed request method benefits by having all configured client params.

hubspotClient.apiRequest({
    method: 'PUT',
    path: '/some/api/not/wrapped/yet',
    body: { key: 'value' },
})

Get contacts

const response = await hubspotClient.apiRequest({
    path: '/crm/v3/objects/contacts',
})
const json = await response.json()
console.log(json)

Upload a file

const formData = new FormData();
const options = {
// some options
};
formData.append("folderPath", '/');
formData.append("options", JSON.stringify(options));
formData.append("file", fs.createReadStream('file path'));

const response = await hubspotClient.apiRequest({
    method: 'POST',
    path: '/filemanager/api/v3/files/upload',
    body: formData,
    defaultJson: false
});

console.log(response);

Reserved words

The SDK has reserved words(e.g. from, in). Full list of reserved words. When you face with a reserved word you have to add _ before the word(e.g. _from, _in).

const BatchInputPublicAssociation = {
    inputs: [
        {
            _from: {
                id : 'contactID'
            },
            to: {
                id: 'companyID'
            },
            type: 'contact_to_company'
        }
    ]
};

const response = await hubspotClient.crm.associations.batchApi.create(
    'contacts',
    'companies',
    BatchInputPublicAssociation
);

Typescript

You may use this library in your Typescript project via:

import * as hubspot from '@hubspot/api-client'
const hubspotClient = new hubspot.Client({ accessToken: YOUR_ACCESS_TOKEN , developerApiKey: YOUR_DEVELOPER_API_KEY })

License

Apache 2.0

Contributing

Install project dependencies with

npm install

You can run the tests by executing:

npm run test

You can check the TypeScript code by running:

npm run lint

If there is a linting error based on formatting, you can run the command below to auto-correct the formatting:

npm run prettier:write

hubspot-api-nodejs's People

Contributors

andrewvasilchuk avatar asalauyeu-hubspot avatar atanasiuk-hubspot avatar dependabot[bot] avatar divslingerx avatar dshukertjr avatar fndicu avatar igorlfs avatar jacquesfu avatar jaggehns avatar jon-armen avatar kaleemmolani avatar kevincolten avatar ksvirkou-hubspot avatar lukiffer avatar mitkofff avatar mwfontes avatar shaddyjr avatar vkhomiv-hubspot avatar yfaktor 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

hubspot-api-nodejs's Issues

Invalid example of AssociationsApi

In the README.md, there is this example code:

await hubspotClient.crm.companies.associationsApi.create(
    createCompanyResponse.body.id,
    'contacts',
    createContactResponse.body.id,
)

But this doesn't build:

src/index.ts:62:87 - error TS2554: Expected 4-6 arguments, but got 3.

 62         const associationResponse = await hubspotClient.crm.companies.associationsApi.create(
                                                                                          ~~~~~~~
 63           createCompanyResponse.body.id,
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
... 
 65           createContactResponse.body.id,
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 66         );
    ~~~~~~~~~

  node_modules/@hubspot/api-client/lib/codegen/crm/companies/api/associationsApi.d.ts:66:73
    66     create(companyId: string, toObjectType: string, toObjectId: string, associationType: string, paginateAssociations?: boolean, options?: {
                                                                               ~~~~~~~~~~~~~~~~~~~~~~~
    An argument for 'associationType' was not provided.

This JSDoc is really not helpful 😦

    /**
     *
     * @summary Associate a company with another object
     * @param companyId
     * @param toObjectType
     * @param toObjectId
     * @param associationType
     * @param paginateAssociations
     */

I assume that toObjectType can be 'contacts' based on the sample code, but what other values are possible?

What are the valid values of associationType? In https://developers.hubspot.com/docs/api/crm/associations, I see only one type "contact_to_company". Is there also a "company_to_contact" type? Where can I find documentation of the other types?

Is there an OpenAPI spec published somewhere with more details about this API?

Consider adding @types/request to dependencies

When I use @hubspot/api-client from TypeScript, I get compilation errors from tsc which complains that it doesn't understand what request is. Not a big deal and easily fixable for the consumer by installing @types/request themselves, but maybe you want to consider bundling this.

Error message is

node_modules/@hubspot/api-client/lib/codegen/marketing/transactional/model/models.d.ts:12:34 - error TS7016: Could not find a declaration file for module 'request'. '/$stuff/node_modules/request/index.js' implicitly has an 'any' type.
  Try `npm i --save-dev @types/request` if it exists or add a new declaration (.d.ts) file containing `declare module 'request';`

getAll properties/options not working?

I'm trying to get all Contacts by using .getAll method.
It works as intended, but I can't seem to request any specific properties.

I've tried:

    const properties = ['company', 'firstname', 'phone', 'address', 'website'];

    const publicObjectSearchRequest = {
        properties,
    }

    const result = await hubspotClient.crm.contacts.getAll(publicObjectSearchRequest);`

but it still returns only firstname, createdAt etc.

this one:

    const properties = [company', 'firstname', 'phone', 'address', 'website'];
    const result = await hubspotClient.crm.contacts.getAll(properties);`

returns "HTTP request failed"

3.1.0 breaks 3.0.1 contacts import

In case anyone has a similar issue, it doesn't look like the README has been updated for importing contacts using streams.

first option with fs.ReadStream.

This will result in an HttpError with the response body

{
  "status": "error",
  "message": "Unable to process JSON",
  "correlationId": "****"
}

I will test further when I get the chance and will add more info in here, but if you need a quick fix just revert back to 3.0.1

Seach method doesnt sort when JSON.stringofy(sortObject)

Hi, i'm having this problem with the doSearch() method that doesn't sort at all if i send the sort array as Array<string>, but if i send it as Array<object> it sorts as expected, the thing is i'm quite sure this is because the internal request method does JSON.stringify over the whole body of the request before sending it so if i do Array<string> it will end with the sorts json being escaped.

This is a request body with Array<string> :
'{"sorts":["{\"propertyName\":\"lastmodifieddate\",\"direction\":\"DESCENDING\"}"]}'

This is the one with Array<object> :
'{"sorts":[{"propertyName":"lastmodifieddate","direction":"DESCENDING"}]'

As you can see they are different but the thing is when programming on typescript the restriction enforces you to use Array<string> or to do sorts as any, but the restriction and the behavior doesn't really correspond to the documentation given.

Model files generated by OpenAPI generator

It would be great to make the OpenAPI files used to generate these models available to customer, for example for usage in Java or Rust.

https://github.com/HubSpot/hubspot-api-nodejs/blob/master/codegen/crm/contacts/model/associatedId.ts

Here you can see OpenAPI (or swagger) source file has been used, but not saved into the repo.

 * Contacts
 * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)

Can a copy be made available on as-id basis?

SimplePublicObjectBatchInput inaccurate type

export declare class SimplePublicObjectBatchInput {
    'properties': {
        [key: string]: string;
    };
    'id': string;
    static discriminator: string | undefined;
    static attributeTypeMap: Array<{
        name: string;
        baseName: string;
        type: string;
    }>;
    static getAttributeTypeMap(): {
        name: string;
        baseName: string;
        type: string;
    }[];
}

I've tested this method by sending property and id that aren't string types and the reuqest successfully updated the object.

Example:

await hubspotClient.crm.contacts.batchApi.update({
      inputs: [
        {
          // eslint-disable-next-line @typescript-eslint/no-explicit-any
          id: 111 as any,
          properties: {
            // eslint-disable-next-line @typescript-eslint/no-explicit-any
            hubspot_owner_id: 12345678 as any,
          },
        },
      ],
    }),

This should really be number and string as many properties are number.

crm.contacts.searchApi.doSearch doesn't work with secondary email

I was unable get the contact with the secondary email. Searching only with principal is working. My result variable return without contacts. However, when I look on HubSpot the relationship was there.

This is my code:

const filter = { propertyName: 'email', operator: 'EQ', value: contact['email'] }

const filterGroup = { filters: [filter] }
const properties = ['email', 'firstname', 'lastname', 'cliente_id']
const limit = 1

const publicObjectSearchRequest = {
    filterGroups: [filterGroup],
    properties,
    limit
};

const result = await hubspotClient.crm.contacts.searchApi.doSearch(publicObjectSearchRequest)```

batchApi update method is not working and returns success with empty array

I inferred the expected structure of your batch update based on your public API docs and the batch create in this libraries readme.

However, it would be helpful if you had an example of how to do a batch update. The bigger problem though is that I believe it is broken.

I've constructed a curl call via API and this works

curl --location --request POST 'https://api.hubapi.com/crm/v3/objects/deals/batch/update?hapikey=redacted' \
--header 'content-type: application/json' \
--data-raw '{
  "inputs": [
    {
      "id": "859408635",
      "properties": {
        "amount": "2"
      }
    }
  ]
}'

However, when I attempt to perform the same using your library, it does not update the record but neither does it throw any errors.

  const dealRecord = [{ id: "859408635", properties: { amount: "1" } }];
  const response = hubspot.crm.deals.batchApi.update(dealRecord);
console.log(response.body.results); //result is []

If this is the incorrect way to perform batch updates can you document that right way?

`iFrameActionBody` seems wrongly typed

According to your documentation here an iFrame action has an uri and not an url. Similarly propertyNamesIncluded should be associatedObjectProperties. Sending an uri fails to render the card correctly.

Here is the doc and your generated code side by side:
image

Thanks

Every call I make gets the MISSING_SCOPES error

Only just getting started with the API and finding the documentation a little unhelpful.

Every call I make get's the MISSING_SCOPES error, regardless of which scopes I activate for the app.

At the same time, I'm not sure if my api key is related to the specific app, or if I should be making some config somewhere?

Sorry for posting such a simple question, but I think this might be a bit of an issue in the docs. 🤔 I'm not a junior developer in any sense (thought I am a total noob with hubspot 😅).

const dotenv = require("dotenv");
const hubspot = require('@hubspot/api-client');
const { CollectionResponsePublicOwner } = require("@hubspot/api-client/lib/codegen/crm/owners/api");

dotenv.config();
console.log('ENV', process.env.API_KEY);
const apikey = process.env.API_KEY;
const hubspotClient = new hubspot.Client({ apiKey: `${apikey}` })

hubspotClient.crm.contacts.basicApi.getPage(10).then(res => { console.log(res, 'SUCCESS') }).catch(err => {
    console.warn(err, err.response, 'ERROR');
})

TypeError: hubspotClient.crm.companies.associationsApi.createAssociation is not a function

TypeError: hubspotClient.crm.companies.associationsApi.createAssociation is not a function

when running your demo code:

const hubspotClient = new hubspot.Client({ apiKey: process.env.API_KEY })
const createContactResponse = await hubspotClient.crm.contacts.basicApi.create(contactObj)
const createCompanyResponse = await hubspotClient.crm.companies.basicApi.create(companyObj)
await hubspotClient.crm.companies.associationsApi.createAssociation(createCompanyResponse.body.id, 'contacts', createContactResponse.body.id)

Question: How would I pass booleans / integers as properties?

Hey,

Loving the new API & the client, I'm just trying to implement it onto our systems now but have realised that

export class SimplePublicObjectInput {
is expecting strings.

This is just a TypeScript concern which I know I can bypass for now but I was wondering if there's something I'm missing in how I'm supposed to be passing booleans / integers through?

sample data:

{
  foo: 1234,
  bar: true,
  ...
}

Cannot read property 'basePath' of undefined

just run this code, no extra step to reproduce this problem:

main.js

const hubspot = require('@hubspot/api-client')
const hubspotClient = new hubspot.Client({
    apiKey: '123456789',
    useLimiter: false
})
hubspotClient.crm.companies.getAll().then(console.log)

log:

~/WebstormProjects/untitled > node main.js
(node:9964) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'basePath' of undefined
    at /home/czp/WebstormProjects/untitled/node_modules/@hubspot/api-client/lib/codegen/crm/companies/api/basicApi.js:328:39
    at Generator.next (<anonymous>)
    at /home/czp/WebstormProjects/untitled/node_modules/@hubspot/api-client/lib/codegen/crm/companies/api/basicApi.js:19:71
    at new Promise (<anonymous>)
    at __awaiter (/home/czp/WebstormProjects/untitled/node_modules/@hubspot/api-client/lib/codegen/crm/companies/api/basicApi.js:15:12)
    at getPage (/home/czp/WebstormProjects/untitled/node_modules/@hubspot/api-client/lib/codegen/crm/companies/api/basicApi.js:327:16)
    at Client.<anonymous> (/home/czp/WebstormProjects/untitled/node_modules/@hubspot/api-client/lib/src/client.js:428:34)
    at Generator.next (<anonymous>)
    at /home/czp/WebstormProjects/untitled/node_modules/@hubspot/api-client/lib/src/client.js:8:71
    at new Promise (<anonymous>)
(node:9964) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 2)
(node:9964) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

node version(test in those version): v10.15.1, v12.18.1
@hubspot/api-client version: ^1.0.0-beta

package.json

{
  "name": "untitled",
  "version": "1.0.0",
  "main": "index.js",
  "license": "MIT",
  "scripts": {
    "start": "node main.js"
  },
  "dependencies": {
    "@hubspot/api-client": "^1.0.0-beta"
  }
}

typescript errors with standard http & request node modules

When running the typescript compiler (tsc), I get the following two errors in a lot places:

import http from 'http';

Module "http" has no default export

You do use import http = require('http'); in another file, which is the proper way to import http. Or you can use import * as http from 'http'

import localVarRequest from 'request';

Module "request" can only be default-imported using the 'esModuleInterop' flag

crm.associations.batchAPI.create does not work as intended

Trying to associate a contact with a company with batch API

  /** @type {import('@hubspot/api-client/lib/codegen/crm/associations/model/publicAssociation').PublicAssociation} */
  const associationRequest = {
    from: '70810',
    to: '5922638459',
    type: 'contact_to_company'
  };

  const result = await client.crm.associations.batchApi.create('contact', 'company', [
    associationRequest
  ]);

 console.log(result.body);

Response Body (no association created / updated):

BatchResponsePublicAssociation {
  results: [],
  numErrors: undefined,
  errors: undefined,
  status: 'COMPLETE',
  requestedAt: undefined,
  startedAt: 2021-06-11T16:08:51.224Z,
  completedAt: 2021-06-11T16:08:51.229Z
}

I also tried with

  /** @type {import('@hubspot/api-client/lib/codegen/crm/associations/model/publicAssociation').PublicAssociation}  */
const associationRequest = {
      from: {
        id: "70810",
      },
      to: {
        id: "5922638459",
      },
      type: 'contact_to_company',
}

Response body is same as above.

Compare this with the cURL example from the docs: https://developers.hubspot.com/docs/api/crm/associations

# @name AssociateContactToCompany
curl --request POST \
  --url 'https://api.hubapi.com/crm/v3/associations/contact/company/batch/create?hapikey={{$dotenv DEV_PORTAL_API_KEY}}' \
  --header 'content-type: application/json' \
  --data '{
  "inputs": [
    {
      "from": {
        "id": "70810"
      },
      "to": {
        "id": "5922638459"
      },
      "type": "contact_to_company"
    }
  ]
}'

Response Body:

{
  "status": "COMPLETE",
  "results": [
    {
      "from": {
        "id": "5922638459"
      },
      "to": {
        "id": "70810"
      },
      "type": "company_to_contact"
    },
    {
      "from": {
        "id": "70810"
      },
      "to": {
        "id": "5922638459"
      },
      "type": "contact_to_company"
    }
  ],
  "startedAt": "2021-06-11T16:18:14.400Z",
  "completedAt": "2021-06-11T16:18:14.468Z"
}

Empty error thrown when using Filter.OperatorEnum

We are attempting to use the crm.deals.searchApi.doSearch method and passing in a PublicObjectSearchRequest with the following format:

const searchRequest: hubspot.dealsModels.PublicObjectSearchRequest = {
        filterGroups: [
          {
            filters: [
              {
                propertyName: 'organization_id',
                operator: hubspot.dealsModels.Filter.OperatorEnum.EQ,
                value: id,
              },
            ],
          },
        ],
        sorts: ['createdAt'],
        properties: ['organization_id'],
        limit: 10,
        after: 0,
      }
const rawDeals = await this._hubspotClient.crm.deals.searchApi.doSearch(
        searchRequest,
      )

The function throws an empty error: {} on the line operator: hubspot.dealsModels.Filter.OperatorEnum.EQ. We have attempted to replace with corresponding string EQ but of course the typescript compiler fails when using that. I was hoping we could get some quick direction on how to properly use these search operator enums in TypeScript. Thanks for all the hard work, this SDK is off to a great start.

Batch associations

We're working on a api to create/update contacts and deals into our hubspot account. Is there a way to associate deals to contacts in batch?

How do I add an existing contact to a ticket?

I am trying to add (associate) an existing contact while creating a ticket. I tried to add "hs_object_id" to the properties. But I am getting VALIDATION ERROR. Kindly assist me with this issue

Properties Batch Create method does not accept properties of type `Property`

I am attempting to bulk-read properties from one hubspot environment to the other with the code below:

  const productionDealResponse = await hubspot.production.crm.properties.coreApi.getAll(
    'deals',
  )
  const prodDealProperies = productionDealResponse.body.results
  await hubspot.development.crm.properties.batchApi.create('deals', {
    inputs: prodDealProperies,
  })
}

However, it appears that the type Property which is returned from getAll is not compatible with the data that the inputs is expecting, namely PropertyCreate. This is the typescript error that I recieve:

Type 'Property[]' is not assignable to type 'PropertyCreate[]'.
  Type 'Property' is not assignable to type 'PropertyCreate'.
    Types of property ''type'' are incompatible.
      Type 'string' is not assignable to type 'TypeEnum'.

And if I try to use .apiRequest with the following signature:

  try {
    const developmentDealProperties = await hubspot.development.apiRequest({
      method: 'POST',
      path: '/crm/v3/properties/deals/batch/create',
      body: {
        inputs: prodDealProperies,
      },
    })
  } catch (e) {
    console.log(e)
  }

I recieve the following error:

      status: 'error',
      message: 'Invalid input JSON on line 1, column 147731: Cannot deserialize value of type `com.hubspot.crmpublic.core.models.schemas.properties.Type` from String "bool": value not one of declared Enum instance names: [number, datetime, date, enumeration, string]',
      correlationId: '74b4cc15-fc60-47d7-b29b-ac165b4326e5'

Is there any way to work around this?

❓SearchAPI: sorts param as Array<string> vs. Array<object> in documentation?

According to the documentation found here the sorts param in the searchApi should be an object array, not a string array, i.e.:

"sorts": [
      {
        "propertyName": "createdate",
        "direction": "DESCENDING"
      }
    ]

In the typing, however, we see that sorts is an Array<string>:

export declare class PublicObjectSearchRequest {
    'filterGroups': Array<FilterGroup>;
    'sorts': Array<string>;
    'query'?: string;
    'properties': Array<string>;
    'limit': number;
    'after': number;
    static discriminator: string | undefined;
    static attributeTypeMap: Array<{
        name: string;
        baseName: string;
        type: string;
    }>;
    static getAttributeTypeMap(): {
        name: string;
        baseName: string;
        type: string;
    }[];
}

Since the README is quite sparse on this, I was hoping to get some clarity on how the sorting should be implemented. Thanks and keep up the good work on this SDK, it's super useful!

v3.2.0 is missing the lib folder

I was just getting started with this API and when I installed the latest (v3.2.0 published an hour ago) the lib folder did not appear to exist at all. Downgrading to v3.1.0 seems to resolve the issue for me.

Deprecated and no longer supported warnings

I just installed the package and got the following warnings.

$ npm install @hubspot/api-client
npm WARN deprecated [email protected]: this library is no longer supported
npm WARN deprecated [email protected]: request has been deprecated, see https://github.com/request/request/issues/3142

added 51 packages, and audited 52 packages in 3s

Are there plans to update the dependencies?

Order blog post descending ascending

We need to be able to retrieve the last 10 blog posts. The current API is by default returning the oldest blog posts. Can we add a param so that we will be able to change the returning of the blogposts in descending order.

Clear a date property via CRM v3 API

I'm trying to clear a date property via create or update contact request with the V3 CRM API. I tried using the empty string "" and also null, but in Hubspot it always shows as "1970-01-01". In Hubspot itself I can clear the field though.

Any idea how to achieve this?

Missing property on Error Type of BatchResponseSimplePublicObjectWithErrors

The Error type is missing the property "category", which is included in the response of the batchApi (Tested with contacts.batchApi.read). I want to check if the error is a 404 and the best way to do that would be to check if the category is "OBJECT_NOT_FOUND". As a workaround i could check the included message or do a typecast to get access to the category property. But would be nice to have the property included in the typedefinitions.

Associations batch API does not use type

When using client.crm.associations.batchApi.createBatch the property type is not added to the request body.

    const associations = {
      inputs: inputList.map(a => ({
        from: { id: a.companyId },
        to: { id: a.contactId },
        type: 'company_to_contact',
      })),
    };
    // This does not take the type 'company_to_contact' into account
    return this.client.crm.associations.batchApi.createBatch(
      'companies',
      'contacts',
      associations,
    );

this works as a workaround though

    return this.client.apiRequest({
      method: 'POST',
      path: `/crm/v3/associations/companies/contacts/batch/create`,
      body: associations
    });

Import .csv file with hs_object_id instead of email as unique parameter?

Is there a possibility to update contact by their unique Hubspot id not email? Is it possible manually in the dashboard by selecting "Update existing contacts using "Contact ID..."

When I'm trying to put e.g. first name, last name (and other fields) + hs_object_id as one of the column I'm getting:

FAILED_VALIDATION,CONTACT,"Property value '956419' isn't valid (from column 'hs_object_id')",2,2,3,956419,28,6

image

remove request and rewrite Client.ts to Discoveries

  • Add Discoveries
  • setAccessToken
  • Add getAll
  • Add Headers
  • basePath
  • Limiter (dep)
  • getAuthorizationUrl
  • validateSignature
  • repair tests
  • repair sample apps
  • hubspotClient.apiRequest
  • add SDK User-Agent to headers (hubspot-api-client-nodejs)

Consider using `axios` rather than `request`

Hi,

request is deprecated since a long time and it's now common to use axios. A lot of generated boilerplate could be removed with this change.

Also, request-promise-core have some unhandled promises which are hanging our apps using @hubspot/api-client. Changing the request library will fix this. Also, the OpenAPI generator used here is capable of generating clients with axios so this change would not be that painful.

I clearly understand that this change will cause some sort of big refactor but I think that it is more than relevant to use a well maintained library, especially if you're relying entirely on it like @hubspot/api-client do:

  "dependencies": {
    "bluebird": "^3.7.2",
    "bottleneck": "^2.19.5",
    "lodash": "^4.17.19",
    "request": "^2.88.0"
  }

You'll be able to remove bluebird, which is nice too.

EDIT: to give more context on why this should be done, some errors are unhandled which is not your fault but is causing some damages. For instance, while trying to edit a CRM contact with a bad id, maybe the error will be catch, maybe not causing the app to hang without being able to catch it:

    StatusCodeError: 404 - {"status":"error","message":"resource not found","correlationId":"xxx"}

      at new StatusCodeError (../../node_modules/request-promise-core/lib/errors.js:32:15)
      at Request.plumbing.callback (../../node_modules/request-promise-core/lib/plumbing.js:104:33)
      at Request.RP$callback [as _callback] (../../node_modules/request-promise-core/lib/plumbing.js:46:31)
      at Request.self.callback (../../node_modules/request/request.js:185:22)
      at Request.<anonymous> (../../node_modules/request/request.js:1154:10)
      at IncomingMessage.<anonymous> (../../node_modules/request/request.js:1076:12)

CRM v3 Associations endpoints do not have support for breaking change announced October 2020?

HubSpot announced a breaking change for responses that return associations data back in October 2020. This change is planned to go live on January 18th.

I’ve been double-checking our support for this and I’ve found that most of the endpoints are already covered by this library (including the ability to pass paginateAssociations=true to get the new behaviour now).

However, it looks like the associations endpoints have been missed?

As an example, the /crm/v3/associations/{fromObjectType}/{toObjectType}/batch/read endpoint cannot be called in this library with paginateAssociations=true, and the it looks like the response types do not include the potential paging data that will be returned when there are more than 100 association results.

{
    "status": "COMPLETE",
    "results": [
        {
            "from": {
                "id": "1"
            },
            "to": [
                // 100 items
            ],
           // no return types for the following paging information
            "paging": {
                "next": {
                    "after": "...",
                    "link": "..."
                },
                "prev": null
            }
        }
    ],
    "startedAt": "2021-01-08T13:30:44.078Z",
    "completedAt": "2021-01-08T13:30:44.086Z"
}

I think this actually means that when the breaking change goes live on the 18th of January, anybody using the associations endpoint won't be able to fetch the additional pages of results?

If you are relying on the associations endpoint today, and expect more than 100 results for some items, I think the only workaround for now is to make calls to that endpoint using hubspotClient.apiRequest as described in the README.

TypeScript Error TS4090 – Conflicting definitions for 'node'

The package has a dependency on @types/node. Using this package in a TypeScript project that also has a dependency on @types/node causes this error:

error TS4090: Conflicting definitions for 'node' found at '<project_path>/node_modules/@types/node/ts3.2/index.d.ts' and '<project_path>/node_modules/@hubspot/api-client/node_modules/@types/node/index.d.ts'. Consider installing a specific version of this library to resolve the conflict.

I believe the accepted best practice for this is to define the @types/* packages as devDependencies and/or peerDependencies to prevent them from being installed in the receiving project's node_modules and allowing the user's project to determine the type definition to use.

templatesApi is not getting developerApiKey from client

If client is initialised with developerApiKey and then crm.timeline.templatesApi is selected to perform request developerApiKey is missing in that request resulting in error "Any of the listed authentication credentials are missing" and status 401.

Only way to get it to work that I found it to explicitly call setApiKey on templatesApi.

Is there anyway to get information on Merged Contacts?

Is there any way on get merge informations when requesting a contact?
If we compare this official api to another npm package
(https://github.com/HubSpotWebTeam/hs-node-api)
i am missing the information on which contacts have been merged into the contact i requested from the API.

In the response from the mentioned package there are two properties which i am missing here:
'merged-vids': string[]; // list of hubspot contact ids
'merge-audits': MergeAudit[];

export interface MergeAudit {
'canonical-vid': number;
'vid-to-merge': number;
timestamp: any;
'entity-id': string;
'user-id': number;
'num-properties-moved': number;
merged_from_email: MergedFromEmail;
merged_to_email: MergedToEmail;
'first-name': string;
'last-name': string;
}
export interface MergedFromEmail {
value: string;
'source-type': string;
'source-id': string;
'source-label'?: any;
'source-vids': number[];
timestamp: any;
selected: boolean;
}
export interface MergedToEmail {
value: string;
'source-type': string;
'source-id': string;
'source-label'?: any;
timestamp: any;
selected: boolean;
}

i hope you can help me.

HubSpotClient.crm.associations.batchApi.createBatch() fails because type isn't serialized

When I try to create an association between a contact and a company it fails because the "type" is either dropped or not serialized correctly on this line. Location @hubspot/api-client/lib/codegen/crm/associations/api/batchApi.js
image

When I edit that line like so:
image
It works as intended.

To create an association I pass in the following data:
{inputs: [
{
from: { id: '4601' },
to: { id: '4021163501' },
type: 'contact_to_company'
}
]}

But the request only sends:
{inputs: [
{
from: { id: '4601' },
to: { id: '4021163501' }
}
]}

Therefore, I keep getting an error response saying [type] is missing;

Companies AssociationsApi createAssociation does not use 'type'

Testet in v0.6.0
if using the client this way:

function createCompanyContactAssociation({
    companyId,
    contactId,
  }) {
    // This results in error in v0.6.0
    return this.client.crm.companies.associationsApi.createAssociation(
      companyId,
      'contacts',
      contactId,
    );
}

The 'company_to_contact' path part is not added to the url and results in an HttpError, that 'type' is missing.

Workaround:

function createCompanyContactAssociation({
    companyId,
    contactId,
  }) {
    return this.client.apiRequest({
      method: 'PUT',
      path: `/crm/v3/objects/companies/${companyId}/associations/contacts/${contactId}/company_to_contact`,
    });
}

Typescript documentation is wrong

Just installed this in a Typescript app. I did:

import Client from '@hubspot/api-client';
const hubspotClient = new Client({ apiKey: '[key]' });

I got This expression is not constructable.

Fixed by destructuring the Client import:

import { Client } from '@hubspot/api-client';
const hubspotClient = new Client({ apiKey: '[key]' });

TimelineEvent class has id set as required, but described as an optional param in the comment

    * Identifier for the event. This is optional, and we recommend you do not pass this in. We will create one for you if you omit this. You can also use `{{uuid}}` anywhere in the ID to generate a unique string, guaranteeing uniqueness.
    */
    'id': string;

TimelineEvent class is currently requiring a value to be passed in for id, but the comment suggests this to be an optional param.

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.