픽골라 스튜디오 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 crAI 작업(콘티 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();