← Blog

How to attach a full call transcript to a HubSpot meeting without truncation

HubSpot property values stop at 65,536 characters. Meeting attachments do not, and the file layer is also the right shape for agents reading your CRM.

Klemen Hrovat · CRO, Sellestial·July 28, 2026·6 min read

HubSpot caps any property value at 65,536 characters, so a long call transcript written into a text property loses its ending. The fix is to stop treating the transcript as a field: upload it as a .txt file through the HubSpot Files API and reference it from the meeting record's hs_attachment_ids. It renders on the activity timeline like any other attachment, it has no practical length ceiling, and an agent or a report can pull the full text back through the API when it needs it.

Why a text property is the wrong home for a transcript

A property truncates silently, and it truncates the end of the call. Across the four client portals where we run Fathom into HubSpot, we currently hold 44 meeting transcripts attached to meeting records. The median is 24,510 characters, measured as the size of the attached .txt file. Three sit past the 65,536-character property ceiling, the longest being a 70,069-character transcript from a single April 2026 working call.

Transcript sizeMeetings (of 44)In a text property
Under 25,00024Fits
25,000 to 50,00014Fits
50,000 to 65,5363Fits, with no headroom
Over 65,5363Cut off

Roughly one call in fifteen loses its tail, and the tail is the expensive part. Pricing pushback, the scope someone quietly agreed to, the next step: those land in the last ten minutes, not the first. Three more sit between 50,000 characters and the ceiling, so a team that prepends a summary or a header to the same property is closer to the wall than it thinks. Longer calls are also the ones worth reading, which means the limit bites hardest exactly where the record matters most.

How to attach the full transcript to a HubSpot meeting

Upload the transcript as a private file through the Files API and write the returned file id onto the meeting record. Five steps, all of them API calls you can run from any notetaker that exposes the full transcript through an API or MCP server:

  1. Find the HubSpot meeting record for the call, or create one when the calendar never produced it.
  2. Upload the transcript text as transcript_<meetingId>.txt, private, through the Files API.
  3. Write the file id into hs_attachment_ids on the meeting, which is what makes it render on the activity timeline.
  4. Keep the AI summary in hs_internal_meeting_notes with one marker line saying the full transcript is attached, so a human reading the timeline knows the long version exists.
  5. Associate the meeting to the contacts and to the companies it belongs to, including the contact's primary company and any company matched by email domain. An unassociated meeting is invisible where people actually look.

One scope detail costs an afternoon if you miss it: reading the attachment back needs the Files read scope on the private-app token. The write path works without it, so the system looks healthy for weeks and then every transcript read returns an error.

The hard part is deciding which meeting a recording belongs to

Uploading the file is ten lines of code. Matching each new recording to the right meeting, exactly once, is the system. Ours works like this:

  • Fathom fires a webhook into a small durable buffer (a Cloudflare Worker with a database behind it) that verifies the signature and holds the event until it is acknowledged, so a laptop reboot never loses a recording. The daemon polls that buffer every 30 seconds.
  • An hourly sweep re-lists the Fathom API over the last 48 hours and picks up anything the webhook path missed. Every webhook integration needs this second path, because a webhook reduces latency and guarantees nothing.
  • Attendees on the recording resolve to HubSpot contacts, contacts resolve to the company, and the company plus the call time resolve to the meeting record. When no meeting exists, the system creates one rather than dropping the transcript.
  • The Fathom recording id is written onto the meeting as a searchable custom property. That makes HubSpot itself the state store: if local state is lost, a search for the recording id finds the meeting again, so a rebuild does not produce a second copy of anything.
  • Re-attaching removes the prior file of the same name first, so a retry replaces the transcript instead of stacking three of them on one meeting.

Internal calls follow a different rule, because a company-scoped transcript is not what anyone wants from a pipeline review. We segment those against a catalog of the 200 most recently modified deals and write each relevant slice as a note on the deal it concerns. Each note is also associated with the deal's companies, which we learned the hard way in July 2026: a company-scoped context pull never sees a note that hangs off the deal alone.

A failed transcript fetch is not an empty transcript

The reader needs three states, not two: transcript present, no transcript, and presence unknown. Ours returns the third one when the Files API answers with a rate limit or a server error, and retries instead of concluding anything. Collapsing unknown into "no transcript" is how an agent silently falls back to the four-line summary and writes a confident brief on thin evidence, with nothing in the output to show that the good source was one retry away. It belongs to the same family of bug as a paginated read that stops after one page and reports that meetings dried up months ago. This is the concrete version of a point we keep making: agents fail on your data, not on the model, and a read path that cannot say "I do not know" is part of your data quality.

The file layer also happens to be the right shape for AI work, which was not the reason we moved but is the reason we would not move back. A context pull fetches the transcript reference only, the file name and its size, and the full text on demand. So an agent can see which meetings have a transcript and how big each one is without dragging every word of every call into its context window. A property is always in the payload whether you want it or not; a file is there when you ask for it. That distinction gets more valuable as more of the reading is done by agents rather than by people.

Put the document in the document layer

If your notetaker writes summaries into HubSpot and your team still opens the recording to check what was agreed, the transcript is not in your CRM yet. Attach the real thing to the meeting, tag it with the recording id so the sync is repeatable, and give the token the scope to read it back. Then the CRM stops being a place where calls are described and becomes a place where they are recorded, which is the precondition for any agent doing useful work on top of it. We build this sync as part of our HubSpot data work: book 30 minutes and bring the longest call your team ever recorded.

FAQ

What is the character limit on a HubSpot property?

A HubSpot property value holds up to 65,536 characters, and text longer than that is cut off when written. Our own email sync caps bodies at 60,000 characters to stay clear of the ceiling. A file attached to the record has no comparable limit, which is why full transcripts belong there.

Can you attach a file to a HubSpot meeting through the API?

Yes. Upload the file through the Files API as a private file, then write its id into the meeting's hs_attachment_ids property. The attachment then appears on the activity timeline next to the meeting, and it can be downloaded again through the API with a signed URL.

Do you need a special scope to read the transcript back?

Yes. The private-app token needs the Files read scope. Uploading and attaching work without it, so the failure only shows up later, when something tries to read the transcript rather than write it.

Should the transcript go on the meeting, the deal, or the company?

Put the transcript file on the meeting record, and associate that meeting to the contacts and companies involved. For internal calls, write the deal-relevant slices as notes on the deals themselves, and associate each note to the deal's companies too, otherwise company-level context pulls will not find it.

Does this work with notetakers other than Fathom?

Yes. Any notetaker that exposes the full transcript through an API or an MCP server can feed the same pipeline, because the HubSpot side of the work is identical: resolve the meeting, upload the file, attach it, and tag the meeting with the recording id for idempotency.

Want this running on your HubSpot?

30 minutes. No pitch deck. Just a conversation about your data.

Talk to us →