It took me some time to figure out how to upload an attachment to a Hubspot Deal, so I’m going to give the details here for others. This article details the steps for NodeJS.

Overall, the Hubspot API has more than one available client for NodeJS:

  • @hubspot/api-client : (github link) The easiest to use so far has been @hubspot/api-client which is what Hubspot directly recommends. It was the easiest interface to use, but it was lacking some functionality such as uploading a file.
  • hubspot : (npm link) This appears to be another common library. Even some of the integration templates provided by Hubspot use this library, so I wouldn’t be surprised if internal Hubspot devs use it as well.
  • You can also use their REST API directly, detailed in the legacy docs, or can use other languages.

For this demo, we’re going to use the hubspot library because @hubspot/api-client doesn’t support file upload.

To get started, install the packages you need:

yarn add hubspot

or if using npm:

npm install --save hubspot

Example Script

To upload a file to a Deal in Hubspot, you first need to upload the file to Hubspot, and then afterwards you create a NOTE Engagement with the uploaded file ID as an attachment to the deal.

const HubspotClient = require('hubspot');
const fs = require('fs');

// Setup an environment variable for the API key (recommended),
const HUBSPOT_API_KEY = process.env.HUBSPOT_API_KEY;
// or add it as a string here.

// Hubspot Deal ID.
const HUBSPOT_DEAL_ID = '<Input_Deal_ID_here>';

const filename = 'testFilename';
// Make sure you have an adjacent file named "testFile.pdf".
const content = fs.readFileSync('./testFile.pdf');

// The folder name in Hubspot to upload files to.
const hubspotFolderPath = 'test-uploads';

const hubspot = new HubspotClient({

const fileOptions = {

  // Prevents external access.
  access: 'PRIVATE',
  overwrite: false,
  // Duplicate files will automatically be renamed
  // with "-1" or "(1)" during upload.
  duplicateValidationStrategy: 'NONE',
  duplicateValidationScope: 'ENTIRE_PORTAL',

const fileDetails = {
  fileName: filename,
  content: content,
  folderPath: hubspotFolderPath,
  options: fileOptions,

.then(resp => {
  // Flatten the response and remove an unneeded key.
  const results = [].concat( => item.objects));

  const attachmentIds = =>;

  const attachments = => ({ id: attachmentId }));

  // Create a NOTE engagement for the deal. We'll include the attachment ID.
  const noteEngagement = {
    engagement: {
      active: true,
      type: "NOTE",
    associations: {
      dealIds: [HUBSPOT_DEAL_ID], // array of deal ids.
    metadata: {
      body: 'Attaching file to Deal.'
    attachments: attachments,

  return hubspot.engagements.create(noteEngagement)
    .then(resp => { console.log('done uploading file')});

Now, you should be able to see the file on the Deal.

You can also view the files by searching in Hubspot for the “Files” or “Documents” section.