UGCDocumentation

Campaign & Slot Endpoints

List, create, fund campaigns and inspect their slots via the Automation Actions API

Updated October 3, 2026
GET/api/automation/actions/campaigns
Required

List, create, fund campaigns and inspect their slots via the Automation Actions API

Rate Limit

This endpoint is limited to 100 requests per 1 minute per API key.

Rate limit headers are included in all responses: X-RateLimit-Limit, X-RateLimit-Remaining

Interactive API PlaygroundTest this endpoint directly from your browser

Credentials

Your API key is never stored and only used for this request

curl -X GET https://api.ugc.africa/api/automation/actions/campaigns \
  -H "Authorization: Bearer YOUR_API_KEY"
Coming soon

SDK examples (coming soon)

JavaScript
// Official Node SDK - coming soon. Use REST (see Getting Started) or fetch() examples.
// Planned: npm install @UGC/node

Official @UGC/* client libraries are on the roadmap. Integrate with the REST API and webhooks today. SDK pages · Email notify

Success

JSON
{
  "id": "..."
}
curl
curl -X GET "https://api.ugc.africa/automation/actions/campaigns?status=ACTIVE" \
  -H "Authorization: Bearer UGSK_live_..."

All endpoints below are under /api/automation/actions and accept a self-serve API key (UGSK_), an Automation connection key (UGAU_), or a portal session JWT - see Server-Side API Overview.

List my campaigns

GET /api/automation/actions/campaigns

Query ParamTypeRequiredDescription
statusstringNoFilter by CampaignStatus (e.g. DRAFT, ACTIVE, PAUSED, COMPLETED)

Response: { "success": true, "data": [ Campaign, ... ] }


Create a campaign

POST /api/automation/actions/campaigns

Creates a DRAFT campaign. It must be funded separately (see below) before it can go ACTIVE.

FieldTypeRequiredDescription
titlestringYesMax 160 chars
descriptionstringNoFull broadcaster brief, max 10,000 chars
campaignTypeenumNoSTANDARD_VIDEO (default), MUSIC_PROMO, MUSIC_PROMO_PRERELEASE, FIXED_FEE, TEXT_DISTRIBUTION, PRODUCT_PLACEMENT, CLIP_CAMPAIGN
campaignModeenumNoDefault BROADCAST
assetsarrayNoCDN URLs plus metadata. There is no upload tool. May be empty on a DRAFT; required before go-live except TEXT_DISTRIBUTION.
payoutTypeenumYesFLAT, CPM_SOCIAL, or CPM_STREAMING (not CPM)
advertiserCpmRatenumberYesUSD per 1,000 views (CPM types) or per post (FLAT).
flatPayoutTiersarrayNoFLAT only - see Performance-tiered flat payouts below
totalBudgetnumberYesTotal campaign budget, USD
maxSlotsnumberNoIgnored for FLAT (server-computed); validated against a cap for CPM_SOCIAL and CPM_STREAMING
targetPlatformsstring[]NoHow channels are set. Platform slugs such as whatsapp_status and snapchat. Omit for all active platforms.
countryAllowliststring[]NoISO country codes; empty = all eligible countries
minKycTiernumberNo0-2, default 1
minCreatorLevelnumberNo1-4, default 1
agencyIdstringNoSolution Partner id for commission attribution

Response: { "success": true, "data": Campaign } (status DRAFT)


Performance-tiered flat payouts

On a FLAT campaign, flatPayoutTiers lets you pay less for a post that gets little verified reach, instead of the full flat rate on every approval. It's optional; omit it and every approved slot pays advertiserCpmRate in full (today's default behavior).

flatPayoutTiers is an array of 1-5 tiers, each a percentage of the campaign's own rate - not a fixed dollar amount, so the same tier table works no matter what rate you set:

json
"flatPayoutTiers": [
  { "minViews": 30,  "payoutPercent": 33 },
  { "minViews": 100, "payoutPercent": 100 }
]
FieldTypeDescription
minViewsintegerVerified view-count threshold for this tier, >= 0
payoutPercentnumberPercent of advertiserCpmRate credited once minViews is met, in (0, 100]

Rules: tiers must be sorted ascending by minViews with both minViews and payoutPercent strictly increasing, and the top tier (largest minViews) must have payoutPercent: 100 - this can only reduce payout for under-performing posts, never raise it above the advertised rate. A verified view count below the lowest tier's minViews pays 0%. Editable only while the campaign is DRAFT or PENDING_FUNDING; frozen once ACTIVE.

This field may be rejected on accounts where the feature isn't yet enabled. If so, the response is a plain 403 Forbidden - see Errors & Troubleshooting.

Once slots start getting approved, each GET .../slots response includes resolvedFlatPayoutPercent on the slot (the percent actually applied, null for untiered or CPM_SOCIAL / CPM_STREAMING campaigns), and the `earnings_credited` trigger tells you in real time whether a credit was full or reduced.


Get a campaign

GET /api/automation/actions/campaigns/:id

Returns the campaign only if it's owned by the authenticated user.


Fund a campaign

POST /api/automation/actions/campaigns/:id/fund

Initiates funding on the chosen rail. The campaign_funded trigger fires once payment settles, moving the campaign toward ACTIVE.

FieldTypeRequiredDescription
methodenumNocheckout (default, in-app card/bank/crypto/MoMo/wallet), payment_link (shareable URL), or wallet (immediate debit)
amountnumberNoUSD amount; required for top-ups, defaults to totalBudget on first funding
currencyenumNoWallet currency when method=wallet; defaults to USD
promoCodestringNoCAMPAIGN_CREDIT promo code

Response returns a checkout URL (checkout / payment_link) or a wallet debit confirmation. See Advertiser Checkout for the funding rails in detail.


List slots for a campaign

GET /api/automation/actions/campaigns/:id/slots

Only the campaign owner may call this.

Query ParamTypeRequiredDescription
statusstringNoFilter by SlotStatus
pagenumberNoDefault 1
limitnumberNoDefault 50, max 200

Response: { "success": true, "data": [ Slot, ... ], "meta": { "total", "page", "limit" } }


Common Errors

400INVALID_CURRENCY

Invalid Currency Code

The currency code provided is not supported.

Example Response
JSON
{
  "success": false,
  "error": {
    "code": "INVALID_CURRENCY",
    "message": "Currency code \"XYZ\" is not supported",
    "supportedCurrencies": [
      "USD",
      "EUR",
      "GBP",
      "GHS",
      "NGN"
    ]
  }
}

Solution: Use a valid ISO 4217 currency code. See our list of supported currencies.

400INSUFFICIENT_BALANCE

Insufficient Wallet Balance

The wallet does not have enough balance to complete this transaction.

Example Response
JSON
{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Insufficient balance in USD wallet",
    "required": 5000,
    "available": 2500
  }
}

Solution: Add funds to your wallet or use a different payment method.

401UNAUTHORIZED

Authentication Required

The request requires authentication but none was provided.

Example Response
JSON
{
  "success": false,
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or expired authentication token"
  }
}

Solution: Include a valid API key or JWT token in the Authorization header.

429RATE_LIMIT_EXCEEDED

Rate Limit Exceeded

Too many requests have been made in a short period.

Example Response
JSON
{
  "success": false,
  "error": {
    "code": "RATE_LIMIT_EXCEEDED",
    "message": "Rate limit exceeded. Try again in 60 seconds",
    "retryAfter": 60
  }
}

Solution: Wait for the specified retry period before making another request. Consider implementing exponential backoff.

Did this solve your problem?