본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 03. 01:22

HubSpot + OpenAI 통합 패턴: 웹훅(Webhooks), 속성(Properties), 그리고 아무도 말해주지 않는 실패 모드

요약

HubSpot과 OpenAI를 통합하여 운영 가능한 AI 워크플로를 구축하는 4가지 기술적 접점과 패턴을 설명합니다. 단순 요약을 넘어 다단계 추론과 구조화된 데이터 쓰기를 구현하기 위한 엔지니어링 가이드를 제공합니다.

핵심 포인트

  • HubSpot 내 서버리스 커스텀 코드는 20초 타임아웃 제한이 있음
  • 장시간 작업이나 큐잉이 필요한 경우 외부 웹훅 방식 권장
  • 대량 작업에는 CRM API를 직접 사용하는 방식이 가장 효율적
  • SLA 요구사항에 따라 적절한 통합 접점을 선택하는 것이 핵심

HubSpot의 기본 AI 기능은 스타터 키트(starter kit)와 같습니다. "이 이메일을 요약해줘"나 "후속 조치 초안을 작성해줘" 같은 작업에는 괜찮습니다. 하지만 HubSpot 워크플로(workflow) 내에서 실제 운영 가능한(production) AI 동작—다단계 추론(multi-step reasoning), 커스텀 검색(custom retrieval), 구조화된 속성(structured properties)으로의 쓰기 작업, 적절한 재시도(retries) 및 감사 로깅(audit logging) 등—을 구현하려는 순간, 여러분은 마케팅 브로슈어를 벗어나 엔지니어링 영역으로 들어서게 됩니다. 이 포스트는 우리가 B2B SaaS RevOps 팀을 위해 첫 번째 HubSpot + OpenAI 통합을 출시하기 전에 읽었더라면 좋았을 내용들을 담고 있습니다.

더 넓은 비즈니스 사례를 알고 싶다면, 제가 일하는 스튜디오인 AltheraCode에 관련 사례 연구가 게시되어 있습니다. 여기서는 비즈니스 사례는 건너뛰겠습니다. 이 글은 엔지니어 대 엔지니어를 위한 글입니다.

AI가 HubSpot 스택에 연결되는 4가지 접점

실질적인 통합 접점은 정확히 네 가지입니다. HubSpot AI 패턴에 대해 읽게 되는 모든 내용은 이 중 하나로 귀결됩니다.

  1. 워크플로 커스텀 코드 액션 (Workflow custom code actions). Node.js를 사용하며, HubSpot 내부에서 서버리스(serverless)로 실행됩니다. 20초의 엄격한 타임아웃(timeout)과 100MB의 메모리 제한이 있습니다. 가장 일반적인 경로입니다. 20초 이내에 완료되는 동기식 데이터 보강(synchronous enrichment)에 적합합니다.
  2. HubSpot 외부로의 웹훅 (Webhooks out of HubSpot). 워크플로 → 귀하의 서비스로 POST 요청 → 귀하의 서비스가 작업 수행 → HubSpot CRM API를 통해 다시 쓰기. 20초 이상의 시간이 필요하거나, 100MB 이상의 메모리가 필요하거나, 큐잉(queueing)이 필요한 경우에 적합한 선택입니다.
  3. CRM API 직접 사용 (The CRM API directly). 앱 구독(app subscriptions)을 통해 폴링(polled)하거나 이벤트 기반(event-driven)으로 작동합니다. HubSpot 외부에서 완전히 운영하며 HubSpot을 REST 엔드포인트를 가진 데이터베이스로 취급합니다. 대량의 벌크 작업(bulk operations)에 가장 좋습니다.
  4. Conversations API 및 타임라인 이벤트 (Conversations API and timeline events). 활용도가 낮습니다. 구조화된 속성(structured properties)을 건드리지 않고도 연락처(contact)나 딜(deal) 타임라인에 AI가 생성한 콘텐츠를 작성할 수 있게 해줍니다. 검색은 필요 없지만 감사가 가능한 "요약" 작업에 탁월합니다.

익숙한 방식이 아니라, 필요한 SLA(Service Level Agreement)에 맞는 접점을 선택하십시오.

패턴 1: 워크플로 커스텀 코드 액션으로서의 리드 의도 보강 (lead-intent enrichment)

가장 흔한 패턴입니다. 연락처(Contact)가 특정 참여 임계값(engagement threshold)에 도달하여 워크플로(workflow)에 진입하면, OpenAI를 호출하고 그 결과를 요약 속성(summary property)으로 다시 기록합니다. 구조는 다음과 같습니다:

exports.main = async (event, callback) => {
  const hubspot = require('@hubspot/api-client');
  const OpenAI = require('openai');
...

제 시간을 낭비하게 만든 세 가지 주의사항이 있습니다.

커스텀 코드 액션(custom code action)의 패키지 목록에 @hubspot/api-clientopenai 패키지를 반드시 명시적으로 추가해야 합니다. HubSpot UI는 올바른 드롭다운 메뉴를 찾아낸 경우에만 이 작업을 자동으로 수행해 줍니다. 저는 이 부분을 놓쳐서 두 시간 동안 헤맸습니다.

event.object.objectId는 신뢰할 수 있습니다. 하지만 event.inputFields는 그렇지 않습니다. UI상에서는 값이 채워진 것처럼 보이는 워크플로 입력값(workflow inputs)이, 특히 속성(property) 이름을 변경한 후에는 undefined로 전달되는 경우가 있습니다. 항상 CRM API를 통해 다시 가져오고(re-fetch), 입력값을 그대로 믿지 마십시오.

구조화된 쓰기 작업(structured writeback)에는 temperature: 0.2 이하를 사용하십시오. 0.7로 설정하면 매주 한 번씩 다운스트림 파싱(downstream parsing)을 망가뜨리는 이상한 문장이 포함된 그럴싸한 요약본이 생성될 것입니다.

패턴 2: 속성 쓰기 기능을 포함한 AI 요약 딜 노트 (AI-summarized deal notes with property writeback)

Gong(또는 Fathom, Granola — 구조는 동일함)에 통화 기록이 남습니다. 여러분은 잠재 고객이 언급한 반대 의견(objection), 타임라인(timeline), 의사결정 기준(decision criteria)을 HubSpot 딜(deal)의 구조화된 속성에 기록하고 싶어 합니다.

초보적인 방식은 자유 형식의 텍스트 요약(free-text summary)을 단일 노트(Note) 속성에 작성하는 것입니다. 프로덕션 버전은 세 개의 별도 커스텀 속성(custom properties)과 함수 호출(function-calling) 응답을 사용하여, 나중에 실제로 파이프라인 분석(pipeline analytics)을 수행할 수 있도록 합니다.

const tool = {
  type: 'function',
  function: {
...

여기서 얻은 두 가지 프로덕션 교훈이 있습니다.

tool_choiceauto 대신 특정 함수로 강제하십시오. auto를 사용하면 모델이 입력값이 함수 호출을 필요로 하지 않는다고 판단할 때, 도구 호출(tool call) 없이 채팅 메시지만 반환하는 경우가 가끔 발생합니다. 워크플로 내부에서는 이러한 불안정성(flakiness)을 허용할 수 없습니다.

decision_criteria 배열의 경우, 다중 선택(multi-select) 모델링을 시도하기보다는 단일 HubSpot 속성에 파이프 기호(|)로 구분된 문자열(pipe-delimited string)로 저장하십시오. HubSpot의 다중 선택 속성은 자유 형식의 텍스트 값을 처리하기에는 제한적이고 취약합니다.

패턴 3: 속성(Properties) 대신 타임라인 이벤트(Timeline events) 사용

사람들은 속성(Properties)이 가장 명확한 단위이기 때문에 이를 먼저 선택합니다. 하지만 파이프라인 보고서(Pipeline reports)의 필터링 기준이 될 데이터는 아니지만, 흥미로운 문맥(Context)이 될 수 있는 AI 생성 콘텐츠의 경우 타임라인(Timeline)에 기록하십시오.

await client.crm.timeline.eventsApi.create({
  eventTemplateId: 'YOUR_TEMPLATE_ID',
  email: contact.email,
...

타임라인 이벤트는 검색이 가능하고 시간순으로 정렬할 수 있으며, 속성(Property) 목록을 어지럽히지 않습니다. 우리는 "연구 요약(Research summaries)", "다음 통화 시 참조할 이전 통화 요약(Previous-call recap on next-call open)", 그리고 "에이전트가 플래그를 지정한 위험 신호(Agent-flagged risk signals)"를 위해 타임라인 이벤트를 사용합니다. "사람을 위한 문맥(Context for a human)"에 해당하는 모든 것은 여기에 들어갑니다. 보고서를 실행할 모든 것은 속성(Property)에 들어갑니다.

실패 모드(Failure modes), 빈도순

제가 직접 겪었던 빈도에 따라 대략적인 순서로 나열했습니다:

워크플로(Workflow) 커스텀 코드 20초 타임아웃. AI 호출(Call)에 데이터 보강(Enrichment) 및 쓰기(Writeback) 작업이 포함되어 20초 이내에 완료되지 않는다면, 반드시 패턴 2(웹훅 외부 호출)로 전환해야 합니다. 저는 어떤 사람들이 이 시간을 "맞추기" 위해 하나의 호출을 두 개의 커스텀 코드 액션(Custom code actions)으로 나누는 것을 보았습니다. 절대 이렇게 하지 마십시오. 그들 사이의 상태 관리(State management)는 악몽과 같습니다. 고통스럽더라도 외부로 분리하십시오.

HubSpot 속도 제한(Rate limits). v3 API의 경우 포털당 10초에 100개의 요청이 제한됩니다. AI 에이전트가 새로운 연락처를 대량으로 보강(Enriching)하고 있다면 이 제한에 걸리게 됩니다. 쓰기 작업 앞에 리키 버킷(Leaky-bucket) 큐를 구현하십시오.

속성 이름 변경 감지(Property rename detection). 마케팅 운영(Marketing ops) 담당자가 Lead_Score_v2Lead Score (V2)로 이름을 변경하면, 코드의 절반이 깨집니다. 속성 메타데이터(Metadata)를 가져와 코드의 예상 스키마(Schema)와 차이점(Diff)을 체크하는 야간 작업(Nightly job)을 구축하십시오.

커스텀 코드 액션 패키지 버전(Custom code action package versions). HubSpot은 런타임(Runtime) 측에서 패키지 버전을 고정(Pin)합니다. 이 글을 쓰는 시점을 기준으로 openai@4.x는 작동하지만, openai@5.x는 작동하지 않습니다. 명시적으로 버전을 고정하십시오.

재시도 시 멱등성(Idempotency on retries). 워크플로는 실패 시 재시도합니다. AI 액션은 반드시 멱등성(Idempotent)을 유지해야 합니다. 즉, 동일한 입력에 대해 동일한 출력 속성 업데이트가 이루어져야 하며, 그렇지 않으면 중복된 타임라인 이벤트가 생성되어 AE(Account Executive)에게 혼란을 줄 수 있습니다. 연락처 ID(Contact ID)와 프롬프트 입력값의 해시(Hash)에서 유도된 요청 ID(Request-ID)를 사용하십시오.

포털에 노출되는 것으로 판명되는 노트(Notes). HubSpot에는 "비공개 노트(private note)" UI 어포던스(affordance)와 "공유 포털 노트(shared portal note)" 속성(property)이 존재하지만, 이 둘은 동일한 것이 아닙니다. 문서를 주의 깊게 읽으십시오. 고객과 공유되는 객체(object)에 영향을 미치는 모든 AI 쓰기 작업(writeback)은 기본적으로 초안 모드(draft-mode)를 사용하십시오.

로깅(Logging) 및 관찰 가능성(Observability)

즐겁지 않은 부분입니다. HubSpot 내부에서 운영되는 프로덕션(Production) AI에는 첫날부터 갖추기 어려운 세 가지 요소가 필요합니다:

  1. 모든 모델 호출을 별도의 저장소에 로깅해야 합니다 (저희는 request_id, contact_id, model, prompt_hash, response, latency_ms, cost_cents를 포함하는 간단한 Cloudflare D1 인스턴스를 사용합니다).
  2. 모든 AI 생성 값과 함께 prompt_version 속성을 기록하여, 히스토리를 잃지 않고 프로덕션 환경에서 프롬프트 A/B 테스트를 수행할 수 있어야 합니다.
  3. 주간 비용 및 품질 보고서입니다. 비용 산출은 쉽습니다. 품질은 영업 운영(sales ops) 리드가 매주 샘플링된 20개의 출력값에 등급을 매기는 작은 스프레드시트입니다. 이 과정을 생략해서는 안 됩니다.

결론

진정한 HubSpot AI 엔지니어링은 모델 엔지니어링(model-engineering)보다는 워크플로우 메커니즘(workflow-mechanics)에 가깝습니다. 모델은 쉬운 부분입니다. 재시도(retries), 속성 위생(property hygiene), 20초 예산(budget), 속도 제한(rate limits), 포털 노출 관련 돌발 상황 — 바로 이 지점에 실제 작업이 존재합니다.

이번 분기에 HubSpot AI 통합(integration)을 출시한다면, 여러분의 스프린트(sprint)를 구해줄 비결은 첫 프롬프트를 작성하기 전에 워크플로우 커스텀 코드 액션(workflow custom code action) 문서를 처음부터 끝까지 정독하는 것입니다.

다른 분들은 속성 이름 변경 감지(property-rename detection)를 어떻게 처리하고 계신지 궁금합니다. 저희는 매일 차이점(diff)을 확인하는 브루트 포스(brute-force) 방식을 사용하고 있습니다. 분명 더 스마트한 방법이 있을 것입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0