How to retrieve files associated with a Custom Object

We have a Custom Object which we read using NodeJS SDK and we have to retrieve attachments uploaded to it.

As we understand so far, attachments are files which resides in the “Notes” association.

By doing this we retrieve all notes from our custom object:

const info = await this.client.crm.objects.basicApi.getById(id_custom_obj, id, props, ['notes']);

So we have the Notes IDs. But retrieving Notes doesn’t yield much:

const note1 = await this.client.crm.objects.basicApi.getById('note', notes[0]);

How it is possible to read files from our object? There’s no “files”, “attachment” or “engagement” associations for our object (at least we can’t see using SDK), but Hubspot Web allows our users to upload documents just fine.

Notes Ids is about as near as we got so far to find some way to get the Files Id, so we can try somehow to get a signed, temporary link to it.

Also, it isn’t possible to read a “schema” for Notes because it isn’t one of our objects, so `

client.crm.schemas.coreApi

can’t be used to retrieve a list of properties or associations for a Note.

Really, trying to use the SDK is a mess. It isn’t documented enough and doesn’t correlate 100% with the API.

Actually, this works:

this.client.crm.schemas.coreApi.getById('note');

It will respond the Note object, and of interest is “hs_attachment_ids” which is a property of Note, not an association.

Thanks for taking the time to follow up and sharing your findings, @FernandoPJ!

— Jaycee

After consulting HS support and trying to use both Node SDK and API, because the SDK has no /files support, much less good docs, what worked for us:

// get our custom object with notes
const custom = await this.client.crm.objects.basicApi.getById(
 id_obj,
 id_crm,
 [properties],
 ['note'],
 );
const notes_ids = custom .body.associations.notes.results.map(({ id }) => id);

// get all notes in batch, retrive file ids from each
const batch_ids: BatchReadInputSimplePublicObjectId = {
 inputs: notes_ids.map((n) => ({ id: n })),
 properties: ['hs_attachment_ids']
}; 
const notes = await this.client.crm.objects.batchApi.read('note', batch_ids);

// flatten all file ids as array
const file_ids = _.flatten(notes.body.results.map((n) => n.properties.hs_attachment_ids.split(','))).join(',');

// retrieve all file URLs from File API
return Promise.all(
 file_ids.map((a) => {
 if (!a || a.length === 0) return null;
 return axios
 .get(`https://api.hubapi.com/files/v3/files/${a}/signed-url`, {
 headers: {
 accept: 'application/json',
 authorization: `Bearer ${private_app_api_access}`,
 },
 })
 .toPromise()
 .then((res) => res.data?.url);
 }),
 );

In the end we get all files as public, signed URLs associated with our custom object.

How to retrieve note attachment files associated with a Custom Object