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.
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.
kb_live_. The signed-in owner can reveal it; rotating invalidates the previous value immediately.403 never removes reporting access.401 response so account existence is never disclosed.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.
{
"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.
| Status | Meaning |
|---|---|
400 | Invalid request or creative |
401 | Invalid credentials |
402 | Billing setup, payment recovery, or exposure cap required |
403 | Campaign write approval or API terms required; reads remain available |
404 | Resource not found |
409 | State or idempotency conflict |
429 | Rate limited; honor Retry-After |
503 | Campaign submission is not operational |
{
"detail": {
"field": "cpm_usd",
"reason": "below_minimum"
}
}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.
curl https://kickbacks.ai/api/advertiser/v1/account \
-H "X-Kickbacks-User-Id: $KB_USER" \
-H "X-Kickbacks-Api-Key: $KB_KEY"{
"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
}
}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.
curl https://kickbacks.ai/api/advertiser/v1/statusList 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.
curl https://kickbacks.ai/api/advertiser/v1/creatives \
-H "X-Kickbacks-User-Id: $KB_USER" \
-H "X-Kickbacks-Api-Key: $KB_KEY"Retrieve a creative
Returns one creative with the same allocation-safe delivery block. Unknown and cross-account IDs use the same 404 response.
curl https://kickbacks.ai/api/advertiser/v1/creatives/$CREATIVE_ID \
-H "X-Kickbacks-User-Id: $KB_USER" \
-H "X-Kickbacks-Api-Key: $KB_KEY"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}.
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"}'Preview a campaign
Snapshots the current owned creative into the same expiring presentation-only page. Revoke it with DELETE /previews/{preview_token}.
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"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
| Granularity | Maximum range |
|---|---|
hour | 31 days |
day | 2 years |
month | 10 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.
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"{
"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 */]
}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.
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"]
}'{
"id": "export_123",
"status": "queued",
"status_url": "/api/advertiser/v1/exports/export_123"
}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.
curl https://kickbacks.ai/api/advertiser/v1/exports/{export_id} \
-H "X-Kickbacks-User-Id: $KB_USER" \
-H "X-Kickbacks-Api-Key: $KB_KEY"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.
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"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
https:// URL without embedded credentials, at most 500 characters.config.min_cpm_usd. Higher bids serve sooner.A-Za-z0-9_.:-. Retrying the same payload and key returns the original campaign.impression (default) or click.false. When true, creates the campaign and receivable but installs the serving kill before any block; call POST /campaigns/{id}/resume to begin delivery.extension or terminal. Send only when config.surface_split_enabled is true.idempotency_key. Reusing a key with a different payload returns 409.start_paused is part of the idempotency contract. Retrying a staged order cannot silently turn it active.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"
}'{
"campaign_id": "campaign_123",
"creation_channel": "advertiser_api",
"status": "active",
"impressions": 10000,
"blocks": 10,
"cpm_usd": 2.0,
"amount_cents": 2000,
"replayed": false
}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.
curl https://kickbacks.ai/api/advertiser/v1/campaigns \
-H "X-Kickbacks-User-Id: $KB_USER" \
-H "X-Kickbacks-Api-Key: $KB_KEY"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.
curl https://kickbacks.ai/api/advertiser/v1/campaigns/{id} \
-H "X-Kickbacks-User-Id: $KB_USER" \
-H "X-Kickbacks-Api-Key: $KB_KEY"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.
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"}'Pause a campaign
Stops serving while preserving auction position. Only active or paused campaigns can use this operation.
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"Resume a campaign
Resumes a paused campaign at its existing auction position and delivery state.
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"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
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"