📝 이 글은 해당 세션 전에 사전 준비 & 프리모템(premortem)을 하면서 작성되었습니다.
본 글은 3편 시리즈의 3편입니다. 1편: 클로드 코드 + 에어브릿지 MCP × API 자동화 청사진 · 2편: 클로드 코드로 OG 이미지 만들고, 에어브릿지 API로 트래킹 링크 N개 발급하기
TL;DR
- 인플루언서 마케팅·자체 SMS·자체 메일·오프라인 행사 같은 공식 통합이 없는 매체의 비용은 마케터가 매주 엑셀에서 따로 관리하다가 ROAS 계산할 때마다 "통합 비용"을 손으로 합칩니다.
- 에어브릿지의 Self-Serve Cost Upload API를 쓰면 CSV 한 번으로 비용·노출·클릭이 대시보드의 Cost (Channel)·Impressions (Channel)·Clicks (Channel) 메트릭에 그대로 녹습니다. 그 다음부터는 통합 ROAS가 자동입니다.
- 이걸 클로드 코드(Claude Code) 에이전트 + cron으로 매일 새벽 돌리면, 마케터는 Google Sheet에 비용을 입력만 하면 됩니다. 나머지는 기계가 처리합니다.
- 단, 공식 통합되어 있는 매체(예: 네이버 검색광고, Meta, Google Ads, TikTok 등)는 self-serve upload 대상이 아닙니다. 에어브릿지 정책상 차단됩니다. 가이드의 schema는 비통합 매체 시연·구현 참고용입니다.
📤 이 글 한 번에 공유하기 — 클로드 코드 + 에어브릿지 REST API + GPT image로 즉석 발급한 트래킹 링크입니다. 채널blog_share, 캠페인airbridge-self-serve-cost-upload-claude-code-automation_202604_blog_share, OG 이미지는 GPT Image 2 (high, 1536×1024). 클릭은 에어브릿지 actuals 리포트에 그대로 집계됩니다.

1. 고질병을 다시 본다
1편 매트릭스에서 짚은 고질병 5(비용·ROAS 통합)와 고질병 1(리포트 빌드·해석)이 만나는 지점입니다.
마케터는 이미 다음 두 가지를 매주 합니다. - 통합된 매체 (Meta·Google·TikTok 등)는 에어브릿지에서 자동 집계 → 대시보드 보고 - 비통합 매체 (인플루언서·자체 SMS·자체 메일·오프라인)는 별도 시트 에서 손으로 합산 → 슬랙·노션 보고
문제는 마지막에 합칠 때. 채널 단위 ROAS, 매체 믹스 기여도, ROI 등을 한 화면에서 보려면 둘이 같은 단위로 들어가 있어야 합니다. 매주 한 명이 1~3시간씩 합치는 일에 쓰입니다. 통합 매체와 비통합 매체를 같은 단위로 합치고 나면, 그 다음에 증분(Incremental) 분석이나 iROAS 비교 같은 한 단계 위 분석으로 넘어갈 수 있습니다.
해결의 핵심은 두 줄기를 같은 집결지로 모으는 일. 에어브릿지 대시보드가 그 집결지가 됩니다.
2. 자동화 흐름 한눈에

[ 마케터가 시트에 비용 입력 ]
- Google Sheet, Notion DB, Airtable 어느 거든
- 컬럼: date, channel, currency, campaign, impressions, clicks, cost, ad_group(선택)
│
▼
[ Cron 매일 06:00 KST ]
│
▼
[ 에이전트 — Sheet → CSV 변환 ]
- 어제까지의 데이터만
- 컨벤션·금지어·타입 검증
- 신규 채널 발견 시 사람 알림
│
▼
[ 에어브릿지 REST API ] POST /self-serve-data/v1/ad-spend/requests
- multipart/form-data로 CSV 업로드
- request_id 반환
│
▼
[ 에이전트 — Status Polling ]
- GET /self-serve-data/v1/ad-spend/requests/{request_id}
- uploaded → validated → ingested → succeeded
- failed 시 reason 분석 → 사람 알림
│
▼
[ 에어브릿지 MCP ] get_actuals_report로 검증
- 어제 비용 (Cost (Channel)) 정상 집계 확인
- anomaly (전일 대비 ±N%) 감지 시 사람 알림
│
▼
[ 슬랙 보고 ]
- 어제 비통합 매체 비용 합계
- 통합 매체와 합산한 매체 믹스 (가시성)
- anomaly 있는 매체 강조
3. 1단계 — Sheet 스키마 설계
에어브릿지의 Self-Serve Cost Upload는 다음 컬럼을 받습니다 (필수와 선택).
| 컬럼 | 타입 | 필수 | 설명 |
|---|---|---|---|
date |
string YYYY-MM-DD |
✅ | 비용 발생일. 앱 타임존 기준. 미래 날짜 불가 |
channel |
string | ✅ | 매체 이름. 공식 통합된 채널명은 사용 불가. 영문 소문자·언더스코어 권장 |
currency |
string | ✅ | ISO 4217 3자리 대문자. e.g. KRW, USD |
campaign |
string | ✅ | 캠페인명. 컨벤션 적용 |
impressions |
int | ✅ | 노출. 콤마 사용 금지 |
clicks |
int | ✅ | 클릭. 콤마 사용 금지 |
cost |
float | ✅ | 비용. 콤마 사용 금지 |
ad_group, ad_creative, term, country, os_name 등 |
string | 선택 | 구체화 시 powerful |
데이터의 식별 키는 (date, channel, campaign) 3종 조합. 같은 키로 두 번 업로드하면 마지막 업로드가 덮어씁니다. 즉 수정도 곧 재업로드. 이 점이 자동화 설계에 큰 영향을 줍니다 — idempotent하게 매일 같은 슬라이딩 윈도우(예: 어제 1일치 또는 어제까지 7일치)를 다시 올려도 안전합니다.
3-1. 시트 권장 구조 (예시)
| date | channel | currency | campaign | impressions | clicks | cost | ad_group |
|---|---|---|---|---|---|---|---|
| 2026-04-28 | influencer_youtube | KRW | spring_2026_megainflu | 120000 | 4500 | 3500000 | yt_megainflu |
| 2026-04-28 | influencer_instagram | KRW | spring_2026_microinflu | 85000 | 3100 | 1800000 | ig_microinflu |
| 2026-04-28 | internal_sms | KRW | spring_2026_loyal_sms | 0 | 12500 | 750000 | sms_loyal |
| 2026-04-28 | offline_event | KRW | spring_2026_seoulmeetup | 0 | 0 | 5000000 | offline_seoul |
(가상 데이터 명시) 위 표의 모든 수치는 시연용 가상값 입니다.
channel 이름 컨벤션은 다음 패턴을 권장합니다. - influencer_{platform} — 인플루언서 마케팅 - internal_{channel} — 자사 보유 채널 (sms, email, push, kakao_msg 등) - offline_{type} — 오프라인 (event, ooh, partnership 등) - partner_{name} — 제휴/공동 마케팅
offline_event처럼 노출·클릭이 무의미한 경우 0 입력. 비용만 집계됩니다. 그래도 cost는 반드시 양수로.
4. 2단계 — Sheet → CSV 변환 (LLM 에이전트의 사전 검증)
LLM 에이전트가 시트를 읽고 CSV로 직렬화하기 전에 다음 검증을 합니다.
# 의사 코드 — 실제 환경에서는 시트 SDK + Anthropic SDK 등 결합
def validate_rows(rows):
integrated_channels = load_integrated_channels() # 에어브릿지 공식 통합 채널 목록 (캐시)
seen_keys = set()
errors = []
for r in rows:
key = (r.date, r.channel, r.campaign)
# 중복 키
if key in seen_keys:
errors.append(("DUP_KEY", r))
seen_keys.add(key)
# 미래 날짜
if r.date > today_in_app_tz():
errors.append(("FUTURE_DATE", r))
# 통합된 채널 사용 시도
if r.channel in integrated_channels:
errors.append(("INTEGRATED_CHANNEL", r))
# 통화 코드
if r.currency not in ISO_4217:
errors.append(("BAD_CURRENCY", r))
# 음수 또는 비숫자
if r.cost < 0 or not is_int(r.impressions) or not is_int(r.clicks):
errors.append(("BAD_NUMBER", r))
return errors
4-1. Human-in-the-loop 지점
검증 결과가 경고(warning)와 오류(error)로 나뉩니다.
- 오류 (e.g. 통합 채널 사용 시도, 미래 날짜, 음수 비용): 업로드 즉시 차단 → 슬랙에 마케터 멘션 → 사람이 시트 수정 후 다음 사이클에서 재시도
- 경고 (e.g. 전일 대비 비용 ±50% 이상 변동 같은 anomaly): 업로드는 진행하되 슬랙에 알림 → 사람이 맞다고 confirm 또는 수정 결정
- 신규 채널 발견 (e.g. 어제까지 없던
influencer_threads가 처음 등장): 업로드 진행하지만 슬랙에 명시적 멘션 → 사람 승인. 첫 등장 채널은 컨벤션·정책 적용 대상
이 3단계 분기가 마케팅 자동화에서 가장 자주 무너지는 지점입니다. 모든 걸 자동으로 흘러보내면 사람이 모르는 사이에 잘못된 데이터가 누적됩니다. 모든 걸 사람 승인 대기로 두면 자동화의 효용이 사라집니다. 위 3분기가 우리가 권하는 균형점입니다.
💡 암묵지 → 명시지 한 번 더 — 위 경고 임계값 (예: ±50%), 오류 차단 룰, 신규 채널 정책은 모두 우리 회사 마케터의 머릿속에서 끌어낸 결과 여야 합니다. 1편에서 정리한 Cognitive Task Analysis 3주 인터뷰 트랙 으로 임계값을 숫자로 박아두면, 같은 ±50% 이상 변동이라도 시즌 정상과 진짜 anomaly를 구분합니다. 그렇지 않으면 에이전트의 권고는 일반론이고, 마케터는 다시 검토 합니다.
5. 3단계 — REST API multipart upload
검증 통과 후 CSV로 직렬화하고 multipart로 업로드합니다.
import FormData from "form-data";
import fetch from "node-fetch";
async function uploadAdSpend(csvBuffer, apiToken) {
const form = new FormData();
form.append("file", csvBuffer, {
filename: `ad_spend_${dayjs().format("YYYYMMDD")}.csv`,
contentType: "text/csv"
});
const res = await fetch(
"https://api.airbridge.io/self-serve-data/v1/ad-spend/requests",
{
method: "POST",
headers: {
"Authorization": `Bearer ${apiToken}`,
...form.getHeaders()
},
body: form
}
);
if (!res.ok) {
const err = await res.text();
throw new Error(`Upload failed: ${res.status} ${err}`);
}
return await res.json(); // { request_id, ... }
}
⚠️ Self-Serve API는 Owner / In-house Marketer 권한의 토큰만 받습니다. 대행사·하위 권한 토큰은 거부됩니다. CI 환경에는 Owner 전용 봇 계정 토큰을 분리해 두는 것을 권합니다.
1회 요청당 최대 10,000행 / 1MB. 큰 시트는 자동으로 chunk 분할이 필요합니다.
6. 4단계 — Status Polling
Self-Serve 업로드는 비동기. request_id를 받은 뒤 다음 상태로 이동합니다.
| 상태 | 설명 | 자동화 분기 |
|---|---|---|
uploaded |
서버에 파일 업로드 완료 | 계속 polling |
validated |
파일 포맷 검증 완료 | 계속 polling |
ingested |
DB에 ingest 완료 | 계속 polling |
succeeded |
리포트에서 조회 가능 (최대 10분 소요) | 다음 단계로 |
failed |
처리 실패. reason 필드 확인 후 사람 알림 |
LLM이 reason 해석 후 슬랙 보고 |
async function pollStatus(requestId, apiToken, maxWaitMs = 15 * 60 * 1000) {
const start = Date.now();
while (Date.now() - start < maxWaitMs) {
const res = await fetch(
`https://api.airbridge.io/self-serve-data/v1/ad-spend/requests/${requestId}`,
{ headers: { "Authorization": `Bearer ${apiToken}` } }
);
const json = await res.json();
const status = json.task?.status;
if (status === "succeeded") return json;
if (status === "failed") throw new Error(`Failed: ${json.reason}`);
await sleep(15_000); // 15초 간격
}
throw new Error("Timeout polling status");
}
7. 5단계 — MCP로 actuals 리포트 검증
업로드 성공 후 그날 cost가 실제로 dashboard에 반영되었는지 MCP로 즉시 검증합니다.
자연어로 호출 시:
"demokr 앱의 어제 날짜, channel별 Cost (Channel)·Impressions (Channel)·Clicks (Channel)을 표로. 어제 self-serve로 올린 4개 채널 (influencer_youtube,influencer_instagram,internal_sms,offline_event) 모두 0이 아닌 값을 가지는지 검증."
MCP는 metadata→report 체인으로 다음을 호출합니다. 1. get_actuals_metrics_metadata — cost_channel, clicks_channel, impressions_channel 키 확인 2. get_actuals_group_by_metadata — channel 키 확인 3. get_actuals_report — 어제 날짜, 4개 채널 필터, 위 메트릭 호출
응답을 받아 LLM이 다음을 판단합니다.
- 4개 채널 모두 cost > 0인가? (offline은 cost만 양수, 나머지 0 허용)
- 어제 시트에 입력한 합계와 일치하는가? (채널별 cost 합산 비교, ±1% 허용 오차)
- 어제 대비 ±N% anomaly 채널 있는가?
판단 결과가 모두 정상이면 슬랙 보고. 하나라도 어긋나면 사람 멘션.
8. 결과 — 30일치 자동 동기화 시연 (가상)
워크샵 데모용 샌드박스에 30일치 가상 데이터를 hourly로 흘려넣고 위 자동화를 돌려보았습니다.
- 시트 입력 (가상 데이터):
- 4개 채널 × 30일 = 120행
influencer_youtube: 일평균 비용 350만원, 노출 12만, 클릭 4.5천influencer_instagram: 일평균 180만원, 노출 8.5만, 클릭 3.1천internal_sms: 일평균 75만원, 노출 0, 클릭 1.25만offline_event: 30일 중 4일만 발생 (이벤트일), 회당 500만원- 자동 업로드 사이클:
- 매일 06:00 KST 트리거
- 평균 처리 시간 (validation → upload → polling → MCP 검증 → 슬랙): 3분 40초
- 사람 개입: 30일 중 4회 (신규 채널 등록 1회, anomaly 감지 3회)
결과 확인 — MCP 자연어 질의:
"4월 한 달간 비통합 매체 합산 비용·노출·클릭을 표로. 통합 매체 (Meta·Google·TikTok)와 합쳤을 때 매체 믹스(%)를 cost 기준으로."
| 매체 그룹 | 합산 비용 | 비중 |
|---|---|---|
| 통합 매체 (Meta·Google·TikTok) | 290억원 | 96.4% |
| 비통합 매체 (인플루언서·SMS·오프라인) | 11억원 | 3.6% |
(가상 데이터 명시) 모든 수치는 시연용 샌드박스 데이터입니다.
9. 도입 시 주의사항
- 공식 통합 채널은 self-serve upload 대상 아님 — 네이버 검색광고, Meta, Google Ads, TikTok 등은 에어브릿지가 자체 OAuth/공식 API로 연동을 제공합니다. self-serve로 올리려 하면 거부됩니다. 통합 가능한 매체부터 통합하고, 그 외만 self-serve로.
- idempotent 설계 — 같은
(date, channel, campaign)키는 마지막 upload가 덮어씁니다. 매일 어제 1일치만 올리지 말고 최근 7일을 매번 다시 올리는 패턴이 안전합니다 (지연 보정). - 데이터 삭제는 영(0) 업로드 — 잘못 올린 데이터를 빼려면 같은 키로
impressions=0, clicks=0, cost=0을 다시 올립니다. 이게 self-serve의 삭제 메커니즘입니다. channel이름 일관성 — 한 번 정한 채널명은 절대 바꾸지 마세요. 바꾸는 순간 이전 데이터가 다른 채널처럼 집계됩니다. 변경이 필요하다면 기존 채널 영(0) 업로드 → 새 채널명으로 re-upload 한 사이클이 필요합니다.- OS 이름은 정확히
Android/iOS— 케이스 센서티브. 잘못 쓰면 행이 분리됩니다.
10. Routines + Managed Agents 패턴 정리

이 흐름의 자동화 단계마다 적합한 패턴이 다릅니다 — 1편 §4에서 정리한 4가지 패턴 중 Routines 와 Managed Agents 가 핵심입니다. 각각의 운영 모델은 Anthropic Claude Code Routines과 Anthropic Managed Agents 개요를 참고하세요. 다음 표는 본 파이프라인에 두 패턴을 어떻게 배치하는지 정리한 것입니다.
| 단계 | 패턴 | 책임자 |
|---|---|---|
| 매일 06:00 트리거 | Routines (cron) | 시스템 |
| Sheet → CSV 직렬화 | LLM 에이전트 (도구 호출) | 시스템 |
| 컨벤션·금지어·타입 검증 | LLM 에이전트 + 룰 엔진 | 시스템 |
| 신규 채널 등록 | Managed Agent → 사람 승인 | 사람 |
| Anomaly 감지 | LLM 에이전트 → 사람 알림 | 사람 |
| API multipart upload | API 호출 | 시스템 |
| Status polling | API 호출 | 시스템 |
| MCP actuals 검증 | MCP 호출 | 시스템 |
| 정기 슬랙 보고 | LLM 에이전트 | 시스템 |
| 정책·룰 변경 | PR 리뷰 | 사람 |
핵심은 데이터·정책의 변화는 사람의 손을 거친다. 반복 작업은 기계의 손으로. 이게 1편에서 정리한 5가지 human-in-the-loop 원칙의 실전 적용입니다.
💡 회사 컨텍스트 주입의 실전 효과 — 1편 §5에서 정리한 회사별 컨텍스트의 4축 중 사업 캘린더 와 사내 의사결정 룰이 이 파이프라인의 anomaly 감지에 직결됩니다. 화장품 D2C라면 "올영 메가세일 주간(매달 셋째주)에는 SMS·메일 비용이 평소의 2~3배까지 정상" 이라는 룰을, 게임 D2C라면 "신규 패치 launch week에는 인플루언서 비용 스파이크 정상" 이라는 룰을 에이전트의 RAG 코퍼스에 박아두면, 같은 ±50% 비용 변동이라도 시즌 정상과 진짜 anomaly를 구분합니다. 이게 비싼 검색엔진 단계에서 진짜 자동화 단계로 넘어가는 분기점입니다.
11. CTA
비통합 매체가 매주 골치라면, 우리 팀의 그로스 스프린트에서 위 흐름을 1주 PoC + 2주 운영 안정화로 깔아드릴 수 있습니다. 첫 1주 안에 어제 비통합 매체 비용이 슬랙으로 자동 보고되는 상태를 만드는 게 목표입니다. 문의는 retn.kr/contact.
마치며
마케팅 자동화에서 완전 자동화는 환상입니다. 진짜 가치는 사람이 의사결정에 시간 쓸 수 있게 만드는 일 입니다. 에어브릿지의 Self-Serve API + MCP + LLM 에이전트 + cron 4가지를 묶으면, 마케터는 시트에 비용을 입력하고 anomaly를 confirm만 하면 됩니다. 나머지 일은 그 사이에 끝납니다.
3편 시리즈를 여기까지 읽어주셔서 감사합니다. 1편 클로드 코드 + 에어브릿지 MCP × API 자동화 청사진 과 2편 블로그 1편을 채널별 트래킹 링크 N개로 도 함께 봐주시면 청사진과 실전이 연결됩니다.
📚 더 읽어보기
- 구글 Meridian으로 마케팅 ROI / 증분(Incremental) 측정
- 채널 포화일 때 진짜 해야 할 일 — 증분을 만드는 스케일업
- 마케팅 대시보드 ROAS가 높은데 매출은 안 느나요? — 증분과 라스트터치
- AI 마케팅 분석: 브레이즈 캔버스 iROAS 19배 달성 사례
- Ghost 뉴스레터 자동화 — n8n + Mailgun으로 Sunset Policy 적용
- 메타 광고 MCP로 3년치 광고 데이터 분석
참고 - Airbridge, Self-Serve Data Upload (REST): https://help.airbridge.io/en/references/self-serve-data.md - Airbridge, 네이버 검색 광고 (공식 통합 가이드, schema 참고용): https://help.airbridge.io/ko/guides/naver-sa - Airbridge, Actuals Report (REST): https://help.airbridge.io/en/references/actuals-report.md