Creator campaigns
Create and activate a creator campaign, invite creators, let them submit through the hosted portal, and approve or reject what they post.
This page takes one CPM campaign from draft to approved submissions. Paying is covered in Pay creators.
#Create the campaign
POST /v1/creator-campaigns with a profileId, a name, a brandName and economics. Send an Idempotency-Key so a retry does not create two campaigns.
curl -X POST https://api.pozy.ai/v1/creator-campaigns \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Idempotency-Key: launch-clips-2026-11" \
-H "Content-Type: application/json" \
-d '{
"profileId": "6650c1f0a2b3c4d5e6f70812",
"name": "Launch clips",
"brandName": "Acme",
"platforms": ["tiktok", "instagram", "youtube"],
"economics": { "type": "cpm", "ratePer1kCents": 100, "minViewsToEarn": 1000, "maxPayoutPerClipCents": 50000, "budgetCents": 500000 },
"contentRules": "Show the product in the first 3 seconds. Tag @acme. No paid boosting.",
"trackingDays": 30,
"holdDays": 10,
"settlement": "treasury"
}'const res = await fetch("https://api.pozy.ai/v1/creator-campaigns", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Idempotency-Key": "launch-clips-2026-11",
"Content-Type": "application/json",
},
body: JSON.stringify({
profileId: "6650c1f0a2b3c4d5e6f70812",
name: "Launch clips",
brandName: "Acme",
platforms: ["tiktok", "instagram", "youtube"],
economics: { type: "cpm", ratePer1kCents: 100, minViewsToEarn: 1000, maxPayoutPerClipCents: 50000, budgetCents: 500000 },
contentRules: "Show the product in the first 3 seconds. Tag @acme. No paid boosting.",
settlement: "treasury",
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.campaign.id, data.campaign.status); // "draft"import os, requests
resp = requests.post(
"https://api.pozy.ai/v1/creator-campaigns",
headers={
"Authorization": f"Bearer {os.environ['POZY_API_KEY']}",
"Idempotency-Key": "launch-clips-2026-11",
},
json={
"profileId": "6650c1f0a2b3c4d5e6f70812",
"name": "Launch clips",
"brandName": "Acme",
"platforms": ["tiktok", "instagram", "youtube"],
"economics": {"type": "cpm", "ratePer1kCents": 100, "minViewsToEarn": 1000, "budgetCents": 500000},
"settlement": "treasury",
},
timeout=30,
)
print(resp.json()["campaign"]["id"])That campaign pays $1 per 1,000 verified views, only once a post passes 1,000 views, at most $500 per post, from a $5,000 budget.
| Field | Default | What it does |
|---|---|---|
platforms |
Any of tiktok, instagram, youtube, threads, pinterest, facebook, twitter |
|
contentRules |
none | Brief shown to creators on their page, up to 10,000 characters |
startsAt, endsAt |
none | Campaign window. Posts published before the start cannot earn. |
trackingDays |
30 | How long each post is tracked, up to 365 |
holdDays |
10 | How long approved earnings are held before they become payable, up to 90 |
maxPostAgeMinutes |
none | Refuse posts submitted longer than this after they were published |
settlement |
none |
treasury pays through Pozy, external means you pay on your own rails and record it, none only tracks |
caps |
maxParticipants, maxSubmissionsPerParticipantPerDay, maxAccountsPerParticipant, maxXReadSpendCents (default $50), authenticityThreshold (0 to 100) |
|
branding |
none | brandName, primaryColor, logoUrl and theme for the creator page |
#Activate, pause, close
| Call | Effect |
|---|---|
POST /v1/creator-campaigns/{campaignId}/activate |
draft or paused to active. If there is no startsAt, activation is the start. |
POST /v1/creator-campaigns/{campaignId}/pause |
Pauses the campaign. Activate it again to resume. |
POST /v1/creator-campaigns/{campaignId}/close |
Ends the campaign. creator_campaign.closed fires. |
POST /v1/creator-campaigns/{campaignId}/budget |
Raise budgetCents, for example after creator_campaign.budget_exhausted |
PATCH /v1/creator-campaigns/{campaignId} |
Edit the campaign |
#Invite creators
Invite one creator by name and email. The response includes their personal inviteUrl.
curl -X POST https://api.pozy.ai/v1/creator-campaigns/6701a2b3c4d5e6f7a8b9c0d1/participants \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "displayName": "Cleo Martin", "email": "cleo@example.com" }'Or create one open link with POST /v1/creator-campaigns/{campaignId}/invite-link and post it anywhere. Everyone who joins through it gets their own personal link. campaign_participant.joined fires when someone joins.
Manage participants with .../participants/{participantId}/suspend, /reinstate, /remove and /resend-invite. Each participant record shows their connected accounts, balances (accruing, owed, payable, settling, settled), flags and payout.status.
#The creator portal
Creators work on a page hosted by Pozy, branded with your campaign branding. If you would rather build your own page, the same actions are public endpoints under /public/creator-campaigns/{token}. They need no API key: the token in the creator's link is the credential.
| Endpoint | What it does |
|---|---|
GET /public/creator-campaigns/{token} |
Read an invite (kind: "invite") or a participant page (kind: "participant") |
POST /public/creator-campaigns/{token} |
Join with an invite token. Returns a participantToken. |
POST /public/creator-campaigns/{token}/connect |
Start connecting a creator account. Returns an authUrl to send them to. |
POST /public/creator-campaigns/{token}/submissions |
Submit a post by url |
GET /public/creator-campaigns/{token}/payouts |
The creator's earnings history |
POST /public/creator-campaigns/{token}/payouts |
Start payout onboarding (action: "onboard"). Returns a url. |
POST /public/creator-campaigns/recover-link |
Email a creator their campaign links by email |
curl -X POST https://api.pozy.ai/public/creator-campaigns/ptok_9fH2kQ/submissions \
-H "Content-Type: application/json" \
-d '{ "url": "https://www.tiktok.com/@cleo/video/7430000000000000000" }'// No API key: the participant token from the creator's link authorizes the call.
const res = await fetch(`https://api.pozy.ai/public/creator-campaigns/${participantToken}/submissions`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://www.tiktok.com/@cleo/video/7430000000000000000" }),
});
const { submission } = await res.json();
console.log(submission.status, submission.trackingEndsAt);import requests
resp = requests.post(
f"https://api.pozy.ai/public/creator-campaigns/{participant_token}/submissions",
json={"url": "https://www.tiktok.com/@cleo/video/7430000000000000000"},
timeout=30,
)
print(resp.json()["submission"]["status"])Treat creator tokens like passwords. Anyone with a participant token can submit posts and start payout onboarding for that creator.
#Submission rules
- The post must come from an account the creator connected, on a platform the campaign allows.
- It must be published after the campaign started. Earlier posts are refused at submission.
- Any post age is accepted unless you set
maxPostAgeMinutes. - All verified views count, including views from before the creator submitted.
minViewsToEarn,maxPayoutPerClipCentsand the budget still apply. - Only views Pozy reads from the platform earn.
#Review submissions
A submission moves through received, tracking, pending_review, then approved or rejected (or expired, withdrawn). It reaches pending_review when a CPM post passes minViewsToEarn, a pool post passes minViewsToQualify, or a per-post submission first accrues. campaign_submission.pending_review fires.
curl "https://api.pozy.ai/v1/creator-campaigns/6701a2b3c4d5e6f7a8b9c0d1/submissions?status=pending_review&sort=viewsEligible" \
-H "Authorization: Bearer $POZY_API_KEY"Filter by status, participantId, platform, flag, an authenticity score range (minScore, maxScore) or text (q), and sort by submittedAt, viewsEligible, earnedCents or authenticityScore.
- Approve:
POST .../submissions/{submissionId}/approve. - Reject:
POST .../submissions/{submissionId}/rejectwith areason(up to 1,000 characters). The creator sees it. - Reopen:
POST .../submissions/{submissionId}/reopenputs a decided submission back up for review.
#Flags
Pozy flags submissions and never rejects them itself. campaign_submission.flagged fires when a new flag appears.
| Flag | Meaning |
|---|---|
duplicate_post, duplicate_media |
The post, or the same media, was already submitted here or to another campaign |
view_spike |
Views jumped sharply between samples |
low_authenticity |
The authenticity score is under the campaign threshold |
linked_accounts, cross_operator |
Signs that accounts are shared with, or run by the same operator as, other participants |
unreachable, post_deleted, account_restricted |
The post or account can no longer be read |
x_read_cap |
The campaign's X read budget is spent, so X views stopped counting |
#Corrections and reporting
POST /v1/creator-campaigns/{campaignId}/adjustmentsrecords anamountCentsadjustment for one participant with acause, such as a bonus or a correction.GET /v1/creator-campaigns/{campaignId}/ledgerlists every money movement on the campaign.GET /v1/creator-campaigns/{campaignId}/reportreturns spend (budgetCents,consumedCents,settledCents), eligible and total views, submission counts, per-participant balances and an authenticity histogram.
#Errors
| Status | Code | Cause | Fix |
|---|---|---|---|
403 |
feature_not_available |
Creator campaigns or treasury payouts are not enabled for the workspace | Contact support@pozy.ai |
#Endpoints
#Webhook events
| Event | When it fires |
|---|---|
campaign_submission.received |
Campaign submission received. |
campaign_submission.flagged |
Campaign submission flagged. |
campaign_submission.pending_review |
Campaign submission pending review. |
campaign_submission.approved |
Campaign submission approved. |
campaign_submission.rejected |
Campaign submission rejected. |
creator_campaign.closed |
Creator campaign closed. |
campaign_participant.joined |
Campaign participant joined. |
campaign_participant.suspended |
Campaign participant suspended. |
campaign_participant.removed |
Campaign participant removed. |
creator_campaign.budget_exhausted |
Creator campaign budget exhausted. |