Skip to content

Developer Platform · v1

API Reference

Programmatic access to Adscod's ad network — advertisers create and manage CPC/CPA/CPM campaigns, and publishers fetch matched native ads with a single Serve call or a one-line script embed. No SDK install required for either side.

Base URLhttps://api.adscod.com/api/v1

Authentication

Adscod has two independent key types, one per side of the network. Use the one that matches your account — they are not interchangeable.

Advertiser key — adc_adv_…

For creating and managing campaigns. Generate one from Advertiser dashboard → Settings → API keys.

curl
curl "https://api.adscod.com/api/v1/external/campaigns" \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE"

Publisher key — adc_pub_…

For requesting ads to serve on your site. Generate one from Publisher dashboard → API keys.

curl
curl "https://engine.adscod.com/api/v1/serve?source=publisher&publisherKey=adc_pub_YOUR_KEY" 

Never expose keys in client-side code. The Publisher SDK script tag is the one exception — it's designed to carry your adc_pub_… key publicly, the same way an analytics snippet does.

There is no creator key. Creators don't integrate programmatically — campaigns are activated on a bio page from the in-app Creator Hub, and the engine matches and serves ads to that page automatically. If you're building a creator-side integration, there's currently no API for it.

Campaigns

adc_adv_ required

Manage CPC, CPA, or CPM campaigns for the advertiser account linked to your API key. Campaigns are created as DRAFT and start serving once you fund your ad wallet (dashboard-only — there is no funding endpoint on this API) and set action: "publish".

POSThttps://api.adscod.com/api/v1/external/campaigns

Create a new campaign. Always starts as DRAFT — publish it with a separate PATCH once your wallet is funded.

Request Body

namestringrequiredInternal campaign name
adTitlestringrequiredHeadline shown to viewers
adBodystringrequiredAd copy shown to viewers
ctaUrlstringrequiredLanding page the click redirects to
ctaLabelstringButton text. Default "Learn More"
adImageUrlstringCreative image URL
budgetUsdnumberrequiredTotal campaign budget
pricingModelenumCPC | CPA | CPM. Default CPC
cpcBidUsdnumberCost per click — required if pricingModel is CPC
cpaBidUsdnumberCost per conversion — required if pricingModel is CPA. Charged at conversion postback, not at click
cpmRateUsdnumberRate per 1000 impressions — required if pricingModel is CPM. Charged per impression at serve time, not per click
actionTypeenumINSTALL | SIGNUP | PURCHASE | LEAD | CUSTOM. CPA conversion type, defaults to CUSTOM
postbackUrlstringYour URL to receive a copy of each conversion (HTTPS only)
dailyCapUsdnumberMax daily spend. Minimum $0.01 if set
categorystringUsed for intent matching at serve time
keywordsstring[]Used for intent matching at serve time
targetCountriesstring[]ISO country codes. Omitted = all countries
targetDevicesstring[]MOBILE | DESKTOP | TABLET. Omitted = all devices
scheduleDaysnumber[]0–6 (Sun–Sat) dayparting. Omitted = every day
scheduleHoursnumber[]0–23 dayparting. Omitted = all hours
frequencyCapnumberMax impressions per viewer per window. Omitted = uncapped

Example Request

curl
curl -X POST https://api.adscod.com/api/v1/external/campaigns \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Summer Launch",
    "adTitle": "Shop the new collection",
    "adBody": "Up to 40% off this week only.",
    "ctaUrl": "https://example.com/deals",
    "budgetUsd": 50,
    "cpcBidUsd": 0.12,
    "targetCountries": ["NG", "KE"]
  }'

Response

json
{
  "success": true,
  "campaign": {
    "id": "cmp_abc123",
    "name": "Summer Launch",
    "adTitle": "Shop the new collection",
    "pricingModel": "CPC",
    "budgetUsd": 50,
    "cpcBidUsd": 0.12,
    "status": "DRAFT",
    "createdAt": "2026-06-30T10:00:00Z"
  }
}
GEThttps://api.adscod.com/api/v1/external/campaigns

List all campaigns for your advertiser account with live stats.

Example Request

curl
curl "https://api.adscod.com/api/v1/external/campaigns" \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE"

Response

json
{
  "success": true,
  "campaigns": [ { "id": "cmp_abc123", "name": "Summer Launch", "status": "ACTIVE", "budgetUsd": 50, "cpcBidUsd": 0.12 } ],
  "stats": { "totalImpressions": 18400, "totalClicks": 340, "totalConversions": 12, "totalSpent": 40.80, "totalBudget": 50, "ctr": 1.85, "conversionRate": 3.53 }
}
GEThttps://api.adscod.com/api/v1/external/campaigns/:id

Get a single campaign you own, plus its 14-day click/spend timeseries.

Parameters

idstringrequiredCampaign ID

Example Request

curl
curl "https://api.adscod.com/api/v1/external/campaigns/cmp_abc123" \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE"

Response

json
{
  "success": true,
  "campaign": { "id": "cmp_abc123", "name": "Summer Launch", "status": "ACTIVE", "budgetUsd": 50, "cpcBidUsd": 0.12, "targetCountries": ["NG", "KE"] },
  "timeseries": [ { "date": "2026-06-29", "clicks": 24, "spend": 2.88 } ]
}
PATCHhttps://api.adscod.com/api/v1/external/campaigns/:id

Update budget, bid, targeting, or copy — or pass action to change lifecycle status. Publishing or resuming requires a funded ad wallet.

Request Body

actionenumpublish | pause | resume | archive
namestring
adTitlestring
adBodystring
budgetUsdnumber
cpcBidUsdnumber
dailyCapUsdnumber
targetCountriesstring[]
keywordsstring[]

Example Request

curl
curl -X PATCH https://api.adscod.com/api/v1/external/campaigns/cmp_abc123 \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{ "action": "publish" }'

Response

json
{ "success": true, "id": "cmp_abc123", "status": "ACTIVE" }
POSThttps://api.adscod.com/api/v1/external/campaigns/conversions

Server-to-server: report a conversion for a CPA campaign once your backend has confirmed it. Pass back the clickId your landing page received as the aff_click_id query param. Idempotent — reporting the same clickId twice is a no-op the second time.

Request Body

clickIdstringrequiredThe aff_click_id your landing page received on the click-through URL
typestringConversion type. Defaults to the campaign's actionType
valuenumberConversion value, for analytics

Example Request

curl
curl -X POST https://api.adscod.com/api/v1/external/campaigns/conversions \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{ "clickId": "clk_9f2a", "type": "PURCHASE", "value": 24.99 }'

Response

json
{ "success": true, "alreadyRecorded": false, "charged": true }

Read-only. Creators choose which campaigns to activate themselves from the Creator Hub — there is no endpoint to assign or invite a creator to a campaign.

GEThttps://api.adscod.com/api/v1/external/campaigns/:id/creators

List creators who have activated this campaign on their bio page, with each creator's clicks and earnings.

Parameters

idstringrequiredCampaign ID

Example Request

curl
curl "https://api.adscod.com/api/v1/external/campaigns/cmp_abc123/creators" \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE"

Response

json
{
  "success": true,
  "campaignId": "cmp_abc123",
  "total": 1,
  "creators": [
    {
      "creatorId": "crt_1",
      "username": "janedoe",
      "displayName": "Jane Doe",
      "verified": true,
      "country": "NG",
      "niche": "fashion",
      "followers": 1000000,
      "isActive": true,
      "clicks": 340,
      "earnedUsd": 26.52,
      "activatedAt": "2026-06-20T09:00:00Z"
    }
  ]
}
GEThttps://api.adscod.com/api/v1/external/creators

Browse the public creator pool — gauge available inventory by niche, follower count, or country before launching a campaign.

Parameters

qstringSearch by name or @username
nichestringe.g. fashion, fintech, gaming
countrystringISO country code
minFollowersnumberMinimum follower count
pagenumberDefault 1
limitnumberDefault 20, max 50

Example Request

curl
curl "https://api.adscod.com/api/v1/external/creators?niche=fashion&country=NG&minFollowers=100000" \
  -H "Authorization: Bearer adc_adv_YOUR_KEY_HERE"

Response

json
{
  "success": true,
  "creators": [
    { "id": "crt_1", "username": "janedoe", "displayName": "Jane Doe", "verified": true, "country": "NG", "niche": "fashion", "followers": 1000000 }
  ],
  "total": 1, "page": 1, "totalPages": 1
}

Ad Serving (Engine)

adc_pub_ required

The serving hot path is a separate Go service at https://engine.adscod.com — not the https://api.adscod.com/api/v1 host used above. It matches active campaigns to a context and returns a short-lived clickUrl; the matching is always a CPC-bid auction boosted by intent/category overlap, not a hard filter, so empty inventory never blocks a response.

Pricing models & payouts

CPC — billed atomically at /click/:token: your cpcBidUsd is debited from the advertiser wallet the instant a click is billed, 65% credited to the creator/publisher wallet, 35% to Adscod.

CPA — the click itself is free: /click/:token records a zero-value attribution row and redirects, no money moves. The charge (and the same 65/35 payout split, applied to cpaBidUsd) happens when the conversion is reported — either POST /api/v1/conversion below, or POST /external/campaigns/conversions from your backend.

CPM — billed on viewability, not on serve: a matched CPM ad is returned for free, and cpmRateUsd / 1000 (same 65/35 split) is charged only once the ad is actually viewed — when your SDK's dwell beacon (POST /api/v1/dwell) reports it as seen. So you are never charged for ads that were returned but never rendered, and a limit=10request that renders 2 bills 2, not 10. Fire the dwell beacon (the SDK does this automatically) or CPM impressions won't bill.

The auction itself always ranks on one number per campaign: cpcBidUsd for CPC/CPA campaigns, cpmRateUsd / 1000 (its per-impression value) for CPM — so campaigns on any pricing model compete for the same inventory on a comparable basis.

GEThttps://engine.adscod.com/api/v1/serve

Match active campaigns to a context and return the best ad(s) plus a one-time clickUrl. This is what the Publisher SDK calls under the hood — call it directly only if you need server-side rendering or custom UI.

Parameters

sourceenumrequiredpublisher (creators use the bio-page flow, not this key)
publisherKeystringrequiredadc_pub_… key. Prefer the X-Adscod-Key header over this query param
placementIdstringYour AdPlacement ID, if you've created one
countrystringISO-3166 alpha-2. Falls back to geo header
devicestringMOBILE | DESKTOP | TABLET
categorystringSoft filter — boosts matching campaigns, doesn't exclude others
qstringRaw search/page-context string, e.g. "cheap bus nairobi mombasa"
limitnumberDefault 1, max 10

Example Request

curl
curl "https://engine.adscod.com/api/v1/serve?source=publisher&placementId=plc_789&country=NG&device=MOBILE&limit=1" \
  -H "X-Adscod-Key: adc_pub_YOUR_KEY_HERE"

Response

json
{
  "success": true,
  "ads": [
    {
      "campaignId": "cmp_abc123",
      "title": "Shop the new collection",
      "body": "Up to 40% off this week only.",
      "imageUrl": "https://…",
      "ctaLabel": "Shop now",
      "clickUrl": "https://adscod.com/click/<clickToken>",
      "cpcUsd": "0.045000"
    }
  ]
}
GEThttps://adscod.adscod.com/click/:token

The clickUrl from /serve. Bills the click (65% to you, 35% platform), then 302-redirects the viewer to the advertiser's ctaUrl. No JSON response — never call this from your backend, only link/redirect viewers to it. Billing failures degrade to a plain redirect, so a viewer never sees an error.

Parameters

tokenstringrequiredThe clickToken embedded in the clickUrl returned by /serve

Example Request

curl
# Not called directly — render clickUrl as a normal <a href> from the /serve response

Response

json
302 Found
Location: https://example.com/deals
POSThttps://engine.adscod.com/api/v1/conversion

Idempotent conversion postback for the hot-path engine. Fired server-to-server from the advertiser's backend with their secret API key (X-Adscod-Key) and the click token from the click-through. The key must never be exposed in browser code. A conversion only matches clicks on your own campaigns. Distinct from /external/campaigns/conversions — use that one for batch S2S CPA reporting instead.

Request Body

clickTokenstringrequiredThe token from the original click
valuenumberConversion value
currencystringDefault USD

Example Request

curl
curl -X POST https://engine.adscod.com/api/v1/conversion \
  -H "Content-Type: application/json" \
  -H "X-Adscod-Key: <YOUR_ADSCOD_API_KEY>" \
  -d '{ "clickToken": "<token>", "value": 12.50 }'

Response

json
{ "success": true, "converted": true, "duplicate": false }

Publisher SDK

no API calls required

For most publishers, the script tag is simpler than calling /api/v1/servedirectly — it auto-detects page category/intent from your page's own meta tags and renders a styled native ad card with no layout work on your side.

html
<script
  src="https://api.adscod.com/sdk/v1/publisher.js"
  data-key="adc_pub_YOUR_KEY_HERE"
  data-placement="banner"
  async
></script>

Script attributes

data-keyRequired. Your adc_pub_… publisher key.
data-placementbanner | sidebar | inline | native. Default banner.
data-categoryPage category. Auto-detected from <meta name="category"> if omitted.
data-themelight | dark. Default light.
data-limitHow many ads to render, 1–3. Default 1.
data-engineEngine base URL override. Default https://engine.adscod.com.

Errors & Rate Limits

HTTP Status Codes

200/201Success
400Validation error — check the response body for details
401Invalid or missing API key
403Key is revoked, or the resource doesn't belong to your account
404Resource not found
429Rate limit exceeded — back off and retry
500Server error — contact support@adscod.com

Rate Limits

Advertiser API keys (adc_adv_…) are limited to 300 requests/minute. Exceeded requests return HTTP 429.

Error Shape

json
{
  "statusCode": 403,
  "message": "API key has been revoked",
  "error": "Forbidden"
}