Skip to content

픽골라 스튜디오 API ​

client.studio는 광고주와 크리에이터가 캠페인 하나를 함께 진행하는 흐름을 다룹니다. 모두 로그인이 필요합니다.

ts
const me = await client.studio.me();
// 광고주 조직(org), 크리에이터 프로필(creator)이 있으면 함께 옵니다.

캠페인 단계 ​

stage화면 이름다음으로 넘기는 쪽
storyboard콘티 검토광고주: approveStory
matching크리에이터 선택광고주: sendOffer
offer제안 응답 대기크리에이터: acceptOffer / rejectOffer
accepted크리에이터 수락광고주: confirmOrder (결제)
producing제작 중AI 광고는 자동, 직접 촬영은 크리에이터 submitOutput
creator_review크리에이터 검수크리에이터: approveOutput / requestRevision / refuseOutput
advertiser_review광고주 검수광고주: approveOutput / requestOutputRevision
approved게시 대기크리에이터: submitProof
published성과 집계양쪽: 성과 입력
done / cancelled완료 / 취소

지금 단계에서 할 수 없는 요청은 409와 함께 지금 단계(…)에서는 할 수 없어요.가 돌아옵니다. 응답의 stageLabel을 그대로 화면에 써도 됩니다.

광고주 ​

조직과 크레딧 ​

ts
await client.studio.org.create({ name: '데모 브랜드', bizNumber: '123-45-67890', email: 'ads@brand.com' });

const idempotencyKey = crypto.randomUUID();
await client.studio.org.chargeCredits({ amount: 100, idempotencyKey }); // 10~10,000 cr

AI 작업(콘티 3안, 수정본, 샘플 영상)은 크레딧을 씁니다. 부족하면 400 CREDITS_REQUIRED입니다. 단가는 client.studio.pricing()으로 확인합니다.

캠페인 만들기 ​

ts
const campaign = await client.studio.campaigns.create({
  productId,
  type: 'AI', // 'AI' | 'Direct'
  brief: { /* 제품 핵심 메시지, 타깃, 금지 표현 등 */ },
});

콘티 3안은 백그라운드 작업으로 만들어집니다. storyboard.status가 generating에서 ready(또는 failed)로 바뀔 때까지 몇 초 간격으로 campaigns.get을 다시 부르세요.

ts
await client.studio.campaigns.selectStory(id, 2);
await client.studio.campaigns.requestRevision(id, { no: 2, note: '첫 장면을 제품 클로즈업으로' });
await client.studio.campaigns.approveStory(id); // → matching

크리에이터 제안과 주문 ​

ts
const creators = await client.studio.creators.list({ category: 'beauty', type: 'AI', sort: 'engagement' });

const quote = await client.studio.campaigns.quote(id, { creatorId, extraMedia: 1 }); // 매체 2개 = 추가 1개

await client.studio.campaigns.sendOffer(id, {
  creatorId,
  channel: 'Instagram',
  format: '릴스 30초',
  postDate: '2026-11-01',
  keep: '3개월',
  assets: ['얼굴', '음성'], // AI 광고에 쓸 자산
  media: ['Instagram', 'TikTok'], // 2개부터 추가 권리비
  region: '국내',
  rightsStart: '2026-11-01',
  rightsEnd: '2027-01-31',
  portfolio: true,
  message: '…',
});

// 크리에이터가 수락하면
await client.studio.campaigns.confirmOrder(id); // 결제 → producing

크리에이터가 자산 사용에 동의하지 않은 범위(매체·지역·기간)로 제안하면 수락 단계에서 409 CONSENT_BLOCKED가 납니다.

검수·게시 이후 ​

ts
await client.studio.campaigns.approveOutput(id);
await client.studio.campaigns.requestOutputRevision(id, '로고를 마지막 2초에 넣어 주세요');
await client.studio.campaigns.addMetrics(id, { metrics: [/* … */] });
await client.studio.campaigns.requestRefund(id, { /* 사유 */ });
await client.studio.campaigns.openDispute(id, { /* 사유와 증빙 */ });

크리에이터 ​

ts
await client.studio.creator.saveProfile({ /* 소개, 카테고리, 채널 */ });
await client.studio.creator.saveRates({ /* 채널별 단가 */ });
await client.studio.creator.savePayoutAccount({ /* 정산 계좌 */ });

const offers = await client.studio.creator.offers();
await client.studio.creator.acceptOffer(campaignId);
await client.studio.creator.rejectOffer(campaignId, { reason: '일정이 맞지 않아요' });

크리에이터 프로필이 없으면 409 CREATOR_REQUIRED, 광고주 조직이 없으면 409 ORG_REQUIRED입니다.

얼굴·음성 자산과 동의 ​

AI 광고에 쓰이는 얼굴·음성은 크리에이터가 직접 올리고, 쓰일 수 있는 범위를 동의서로 정합니다.

ts
const ticket = await client.uploads.ticket({ purpose: 'asset', contentType: file.type, size: file.size });
await fetch(ticket.uploadUrl, { method: 'PUT', headers: ticket.headers, body: file });

const asset = await client.studio.creator.uploadAsset({ kind: 'face', desc: '정면 사진', fileUrl: ticket.url });

await client.studio.creator.updateConsent(asset.id, {
  media: ['Instagram', 'TikTok'],
  region: '국내',
  start: '2026-10-01',
  end: '2027-09-30',
  paid: true,
  secondary: false,
  portfolio: true,
  showcase: false,
  agreed: true,
});

await client.studio.creator.revokeConsent(asset.id, '더 이상 사용을 원하지 않아요');

자산은 운영팀 검수를 통과해야 제안에 쓸 수 있습니다. 동의를 철회하면 이후 새 제안에는 쓰이지 않습니다.

결과물·게시 증빙·정산 ​

ts
await client.studio.creator.submitOutput(campaignId, { outputUrl: ticket.url, note: '…' }); // 직접 촬영
await client.studio.creator.approveOutput(campaignId); // AI 결과물 검수
await client.studio.creator.submitProof(campaignId, { url: 'https://instagram.com/p/…', captures: 2 });

const payouts = await client.studio.creator.payouts();