Kickbacks.ai API reference

Advertiser API

Create and manage campaigns programmatically. API orders enter the same live, price-ranked auction as orders from the web portal.

The base URL for every endpoint in this reference is:

https://kickbacks.ai/api/advertiser/v1

Requests and responses use JSON. For a machine-readable contract, download the OpenAPI 3.1 specification. To delegate the whole workflow—including skill setup and post-create verification—use the single Claude document.

Download unified .md
Checking current status…Current state only · no historical uptime claim
BASE URL
https://kickbacks.ai/api/advertiser/v1

Authentication

Send both credentials as headers on every request. Your key is pre-generated in the advertiser portal under API access and stays hidden until you click Show.

X-Kickbacks-User-Idstringrequired
The user ID displayed beside your API key.
X-Kickbacks-Api-Keystringrequired
Your secret key, beginning with kb_live_. The signed-in owner can reveal it; rotating invalidates the previous value immediately.
Access model: every authenticated advertiser can read account, campaign, creative, metric, preview, and export data. Creating or changing campaigns is manually approved and also requires accepting the Advertiser API terms in the portal. A write-access 403 never removes reporting access.
Keep API keys out of source control and client-side code. Authentication failures return the same 401 response so account existence is never disclosed.
AUTHENTICATED REQUEST
curl https://kickbacks.ai/api/advertiser/v1/account \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"

Billing

Campaign writes require an operational billing arrangement. Choose weekly saved-card auto-pay or request separately approved Net 30; neither requires campaign prepayment, and both bill authoritative delivered value.

amount_cents on create is the order's maximum face-value estimate, not an immediate charge. The invoice uses billable delivery targeting ten continuous seconds, with measured dwell accepted from 9.5 seconds, as recorded by the authoritative ledger. Adjustment credits apply automatically to the next finalized invoice.

BILLING MODE
{
  "currency": "usd",
  "billing": "weekly_autopay"
}

Errors

Non-2xx responses include detail, either as a string or an object naming the invalid field and reason. Unknown campaign IDs and campaigns owned by other accounts both return 404.

StatusMeaning
400Invalid request or creative
401Invalid credentials
402Billing setup, payment recovery, or exposure cap required
403Campaign write approval or API terms required; reads remain available
404Resource not found
409State or idempotency conflict
429Rate limited; honor Retry-After
503Campaign submission is not operational
ERROR RESPONSE
{
  "detail": {
    "field": "cpm_usd",
    "reason": "below_minimum"
  }
}
GET/account

Retrieve account and balance

Returns identity, the complete invoiced-account balance, and live ordering constraints. Call this before creating a campaign instead of hard-coding limits.

access.reporting is operational or degraded. degraded means the daily rollups have fallen behind, so /stats reads fall through to live ledger scans and large or unaligned windows may be slow or refused. Reporting still answers — prefer last_days and narrower windows until it clears.

balance.owed_cents combines unbilled delivered value and finalized unpaid invoices, less posted adjustment credits. billing_profile reports enrollment, tax readiness, payment health, and the next 1st/15th collection date.

REQUEST
curl https://kickbacks.ai/api/advertiser/v1/account \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
RESPONSE
{
  "user_id": "user_123",
  "outstanding_cents": 0,
  "currency": "usd",
  "billing_email": "ads@acme.dev",
  "billing": "delivered_value_postpay",
  "balance": {
    "owed_cents": 0,
    "pending_cents": 0,
    "invoiced_cents": 2000,
    "paid_cents": 2000,
    "credits_cents": 0,
    "next_invoice_at": "2026-09-01T06:00:00Z"
  },
  "config": {
    "block_impressions": 1000,
    "min_cpm_usd": 0.5,
    "max_blocks": 100,
    "outstanding_balance_cap_usd": 500
  }
}
GET/status

Retrieve current component status

Returns passive current state for the API endpoint, site proxy, authentication, campaign creation, reporting, exports, and invoicing. States are operational, degraded, disabled, or unknown. This endpoint makes no write and reports no invented historical uptime percentage.

REQUEST
curl https://kickbacks.ai/api/advertiser/v1/status
GET/creatives

List creatives

Returns owned creatives (currently bounded to 500) with presentation, moderation, targeting, pacing, allocation-safe inventory, block delivery, and remaining inventory. Collection reads set delivery.metrics_availability to temporarily_unavailable and return ledger-derived billable impressions, clicks, CTR, viewable ticks, unique viewers, spend, and observed served timestamps as null; use bounded /stats or retrieve one creative when those metrics are required. A null is never a measured zero. Inventory is creative-level only when bid_blocks.creative_id proves the allocation; legacy inventory returns allocation_status: campaign_only and campaign totals instead of a fabricated creative remainder.

REQUEST
curl https://kickbacks.ai/api/advertiser/v1/creatives \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
GET/creatives/{creative_id}

Retrieve a creative

Returns one creative with the same allocation-safe delivery block. Unknown and cross-account IDs use the same 404 response.

REQUEST
curl https://kickbacks.ai/api/advertiser/v1/creatives/$CREATIVE_ID \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
POST/preview

Preview an unfunded creative

Validates a creative without creating a campaign, block, charge, or ledger row. Returns a 24-hour preview_url showing terminal and extension surfaces. The public snapshot carries presentation fields only and can be revoked with DELETE /previews/{preview_token}.

Preview pages have no impression, ten-second billable view, click, redirect, supplier pixel, auction, or telemetry path.
REQUEST
curl -X POST https://kickbacks.ai/api/advertiser/v1/preview \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY" \
  -H "Content-Type: application/json" \
  --data '{"ad_line":"Deploy faster with Acme Cloud","destination_url":"https://acme.dev","target_surface":"both"}'
POST/campaigns/{id}/preview

Preview a campaign

Snapshots the current owned creative into the same expiring presentation-only page. Revoke it with DELETE /previews/{preview_token}.

REQUEST
curl -X POST https://kickbacks.ai/api/advertiser/v1/campaigns/$CAMPAIGN_ID/preview \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
GET/stats

Retrieve delivery stats

Returns stable account-level ledger metrics and a time series. Ask for a window with last_days=N (recommended) or an explicit start/end. Filter by one or more campaign IDs, creative IDs, surfaces, or countries using comma-separated query values. Filters are intersected and every campaign is checked against the authenticated account. For apples-to-apples A/B data, pass group_by=creative with comma-separated creative_id values; every series uses the same UTC [start,end) bucket spine and includes explicit zeroes.

Time resolution

GranularityMaximum range
hour31 days
day2 years
month10 years

Relative windows — prefer last_days

last_days=N returns the last N complete UTC days and is the cheapest, safest way to read this endpoint. The server computes the bounds, so they are whole-day aligned by construction and served from the pre-aggregated daily rollups. Bounds you build from your own clock usually are not aligned, and a few minutes of drift off midnight silently costs a full ledger scan. last_days=7 is identical to sending no window at all. It cannot be combined with start or end (400, conflicting_window), and it still obeys the per-granularity range ceiling above.

Default window

start and end are optional. Omitting both at day granularity returns the last seven complete UTC days: the exclusive end is normally today’s midnight, and may be a day earlier while that day is still rolling up. Every response echoes the exact start and end it measured, so read those rather than assuming them. Explicit bounds are always honoured verbatim and never rounded.

Stable metric fields

billable_impressions, viewable_ticks, clicks, events, unique_viewers, spend_micros, and ctr on both totals and every point. Total unique viewers are distinct across the entire requested interval; point values are distinct within each bucket and must not be summed.

Which store answered

Every response carries served_from, and it predicts cost. daily_rollup is pre-aggregated closed UTC days — fast, and flat as the account grows. You get it at day or month granularity when both bounds sit on UTC midnight and no country filter is set. ledger is a live scan whose cost grows with window length multiplied by delivery volume; four shapes always need it, by design: granularity=hour, any partial trailing day such as an end of “now”, any country filter, and group_by=creative. For scheduled ingestion, prefer whole-UTC-day bounds and check that served_from is daily_rollup.

Windows that are too expensive

A window that would require a provably oversized live scan is refused immediately with 400 and detail.reason of window_too_costly, rather than being allowed to run until it times out. The detail carries estimated_events, max_events, and usually a retry_with object naming bounds that will work. retry_with never repeats the window you just sent, so it is always safe to follow; it is absent when no alternative window would help.

REQUEST
curl "https://kickbacks.ai/api/advertiser/v1/stats?last_days=30&granularity=day&campaign_id=campaign_123,campaign_456" \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
RESPONSE
{
  "granularity": "day",
  "served_from": "daily_rollup",
  "totals": {
    "billable_impressions": 12040,
    "viewable_ticks": 12040,
    "clicks": 91,
    "unique_viewers": 4821,
    "spend_micros": 24080000,
    "ctr": 0.007558
  },
  "points": [/* same metric fields + bucket + ctr */]
}
POST/exports

Create a raw-ledger CSV export

Queues an asynchronous export for a bounded time interval. The default maximum is 31 days and 250,000 rows; operators can lower those limits. Use the same campaign, creative, surface, and country filters as stats.

Privacy boundary: exports contain timestamp, event type, campaign, creative, surface, country, billable status, and advertiser debit only. Viewer IDs, client IDs, IP hashes, and other network identifiers are never exported.
REQUEST
curl -X POST https://kickbacks.ai/api/advertiser/v1/exports \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "start":"2026-08-01T00:00:00Z",
    "end":"2026-08-08T00:00:00Z",
    "campaign_ids":["campaign_123"]
  }'
202 ACCEPTED
{
  "id": "export_123",
  "status": "queued",
  "status_url": "/api/advertiser/v1/exports/export_123"
}
GET/exports/{export_id}

Retrieve export status

Poll until status is ready or failed. Ready jobs include download_url, row count, size, expiry, and the CSV schema_version the artifact was generated under (ledger-export-v2; jobs queued under an older contract keep reporting theirs). Downloads expire after 24 hours by default.

REQUEST
curl https://kickbacks.ai/api/advertiser/v1/exports/{export_id} \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
GET/exports/{export_id}/download

Download an export

Streams the private CSV through the authenticated API. The response is marked private, no-store and includes X-Kickbacks-Export-Schema plus X-Kickbacks-Content-SHA256 so clients can validate the schema and bytes before parsing. A job that is still running returns 409; an expired job returns 410.

REQUEST
curl -o ledger.csv https://kickbacks.ai/api/advertiser/v1/exports/{export_id}/download \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
POST/campaigns

Create a campaign

Creates a campaign and, by default, enters it into the live auction. Set start_paused: true to stage it behind the authoritative serving kill switch until you explicitly resume it. A successful request returns 201.

Parameters

ad_linestringrequired
Creative text, 3–60 characters. Around 30–40 characters renders best. Control characters and unsafe content are rejected.
destination_urlstringrequired
An https:// URL without embedded credentials, at most 500 characters.
cpm_usdnumberrequired
Bid per 1,000 impressions. Must meet config.min_cpm_usd. Higher bids serve sooner.
impressionsintegerrequired
1,000–100,000 in multiples of 1,000 nominal ten-second viewable impressions (9.5-second measured floor).
idempotency_keystringrequired
A unique order reference, 1–64 characters using A-Za-z0-9_.:-. Retrying the same payload and key returns the original campaign.
brandstringoptional
Public brand name, at most 120 characters.
namestringoptional
Private dashboard label, at most 120 characters.
kindenumoptional
impression (default) or click.
pace_minutesintegeroptional
Spread delivery over 1–10,080 minutes. Omit for fastest delivery.
start_pausedbooleanoptional
Default false. When true, creates the campaign and receivable but installs the serving kill before any block; call POST /campaigns/{id}/resume to begin delivery.
icon_urlstringoptional
HTTPS URL or data URI, at most 12,000 characters.
target_surfaceenumoptional
extension or terminal. Send only when config.surface_split_enabled is true.
target_countriesarrayoptional
Up to 20 ISO 3166-1 alpha-2 codes. Send only when country targeting is enabled.
Safe retries: Retry a timed-out create only with the same idempotency_key. Reusing a key with a different payload returns 409.
Stage before launch: start_paused is part of the idempotency contract. Retrying a staged order cannot silently turn it active.
REQUEST
curl -X POST https://kickbacks.ai/api/advertiser/v1/campaigns \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY" \
  -H "Content-Type: application/json" \
  --data '{
    "ad_line": "Shipping faster with Acme…",
    "destination_url": "https://acme.dev",
    "brand": "Acme",
    "cpm_usd": 2.00,
    "impressions": 10000,
    "idempotency_key": "acme-launch-2026-08-a"
  }'
RESPONSE
{
  "campaign_id": "campaign_123",
  "creation_channel": "advertiser_api",
  "status": "active",
  "impressions": 10000,
  "blocks": 10,
  "cpm_usd": 2.0,
  "amount_cents": 2000,
  "replayed": false
}
GET/campaigns

List campaigns

Returns campaigns owned by the authenticated account, including the strongly typed creation_channel provenance field, status, current creative, moderation status, delivered value, block-level delivery, and report links. API-created records are advertiser_api; legacy means the record predates provenance stamping.

REQUEST
curl https://kickbacks.ai/api/advertiser/v1/campaigns \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
GET/campaigns/{id}

Retrieve a campaign

Returns one campaign and its delivery blocks. Sum impressions_served across blocks for total delivery. Block status progresses from queued to serving to exhausted.

REQUEST
curl https://kickbacks.ai/api/advertiser/v1/campaigns/{id} \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
PATCH/campaigns/{id}

Update a campaign

Updates name, ad_line, or both. A new creative is validated and screened before replacing the live creative. To change URL, bid, or size, cancel and create a new campaign.

REQUEST
curl -X PATCH https://kickbacks.ai/api/advertiser/v1/campaigns/{id} \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY" \
  -H "Content-Type: application/json" \
  --data '{"ad_line":"Build faster with Acme"}'
POST/campaigns/{id}/pause

Pause a campaign

Stops serving while preserving auction position. Only active or paused campaigns can use this operation.

REQUEST
curl -X POST https://kickbacks.ai/api/advertiser/v1/campaigns/{id}/pause \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
POST/campaigns/{id}/resume

Resume a campaign

Resumes a paused campaign at its existing auction position and delivery state.

REQUEST
curl -X POST https://kickbacks.ai/api/advertiser/v1/campaigns/{id}/resume \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"
DELETE/campaigns/{id}

Cancel a campaign

Permanently stops delivery. Delivered impressions are billed pro rata; undelivered impressions are never billed. Cancellation cannot be reversed.

Questions or higher limits? support@kickbacks.ai

REQUEST
curl -X DELETE https://kickbacks.ai/api/advertiser/v1/campaigns/{id} \
  -H "X-Kickbacks-User-Id: $KB_USER" \
  -H "X-Kickbacks-Api-Key: $KB_KEY"