Skip to main content

Campaign Management API

Use the Campaign Management API to manage your Pushnami Ads account from your own scripts, tools or AI agents. It covers the changes advertisers make most often in the dashboard:

  • Campaigns: create, clone, rename, pause, activate and archive. Change bids, daily spend limits, target CPA, audience and schedule.
  • Creatives: create, edit, clone, pause, activate and archive push creatives. Upload images and icons.
  • Sources: set bids for many sources at once, and block, unblock, allow or disallow sources.

The same actions are available as an MCP server, so you can connect Claude, Cursor or another MCP-capable agent to your account. If you want an agent to set itself up, point it at the Agent Guide.

What this API does not do
  • Billing: adding funds, payment methods, auto-funding and invoices stay in the dashboard. You can check your balance, but not change it.
  • Reporting: for spend and performance data, use the Spend Report API.

Quick Start​

1. Create an API key. In the dashboard, open API Access in the side menu and select Create Key. Give it a name, choose Read only or Read & write, and confirm your password. The key is shown only once, so copy it then.

You can also create a key from the command line with your Pushnami Ads username and password:

curl -u 'you@example.com:your-password' \
-H 'Content-Type: application/json' \
-d '{"name": "my first key", "scope": "write"}' \
https://ads-api.pushnami.com/v1/api-keys
{
"key": "pnk_3f9c1a0b2d4e6f8a1b2c3d4e_Xk2...",
"key_id": "3f9c1a0b2d4e6f8a1b2c3d4e",
"name": "my first key",
"scope": "write",
"expires_at": "2027-09-24T15:02:11.000Z"
}

Copy key from the response. It isn't shown again. The key lasts 365 days unless you add "expires_in_days": 30 or 90.

2. Call the API with the key as a Bearer token.

curl -H 'Authorization: Bearer pnk_...' \
https://ads-api.pushnami.com/v1/campaigns

API Keys​

PropertyDetails
Formatpnk_ followed by a key ID and a secret
Scoperead (view only) or write (view and change). Defaults to read.
Lifetime30, 90 or 365 days, chosen when you create the key. The default is 365.
Limit10 active keys per account
Sending itAuthorization: Bearer pnk_... (or X-API-Key: pnk_...)

A key acts as your account and nothing else. It can never see or change another advertiser's campaigns.

Expiry and Renewal​

Renew a key on the API Access page in the dashboard by entering your password again. The key string stays the same, so nothing that uses it needs to change. You can renew a key before or after it expires, but not after it is revoked. Renewing an expired key counts toward the limit of 10 active keys.

Every response to a request made with a key tells you when the key expires:

HeaderWhenValue
Pushnami-Api-Key-Expires-AtAlwaysThe expiry time, for example 2027-09-24T15:02:11.000Z
Pushnami-Api-Key-Expiry-WarningIn the last 14 daysFor example Key expires in 5 days. Renew it on the API Access page.

Over MCP, tool results carry the same warning as key_expiry_warning in the last 14 days.

We also email the account's alert address (or its contact address if it has none) 14 days and 3 days before a key expires.

A key also stops working when your Pushnami Ads login is disabled, when you are removed from the account, or when your password is reset.

Using keys safely

  • Give each script or agent its own key, so you can revoke one without breaking the others.
  • Use a read key for anything that only needs to look, such as a monitoring agent or a dashboard.
  • Keep keys out of source control and chat messages. Store them in a secrets manager or environment variable.
  • If a key leaks, revoke it right away (see Manage Keys).

Manage Keys​

The API Access page in the dashboard lists your keys with when each was created, last used and expires, and lets you revoke any of them.

You can do the same over the API. Listing returns only metadata, never the key itself.

curl -H 'Authorization: Bearer pnk_...' https://ads-api.pushnami.com/v1/api-keys

Revoke a key with any write key, or with the key itself:

curl -X DELETE -H 'Authorization: Bearer pnk_...' \
https://ads-api.pushnami.com/v1/api-keys/3f9c1a0b2d4e6f8a1b2c3d4e

If you've lost the key, revoke it with your login instead:

curl -X DELETE -u 'you@example.com:your-password' \
https://ads-api.pushnami.com/v1/api-keys/3f9c1a0b2d4e6f8a1b2c3d4e
Logins with multi-factor authentication

You can't create a key from a login that needs an extra sign-in step, such as MFA or a required password change. Finish that step in the dashboard first. If your organization requires MFA, contact your account representative.

Conventions​

  • Base URL: https://ads-api.pushnami.com
  • IDs: campaigns look like C0001234, creatives like C0001234-001. Sources use the same website IDs as the source_id column in the Spend Report API.
  • Money: USD. Bids are per click.
  • Dates: RFC 3339, for example 2026-10-01T00:00:00Z.
  • Requests: JSON bodies. Unknown fields are rejected, so a typo produces an error instead of being ignored.
  • Lists: use limit (1–100, default 25) and offset. Responses include pagination.total.
  • Machine-readable spec: /v1/openapi.json (OpenAPI 3.1).
  • Usage analytics: as in the dashboard, we record which operations each key calls, whether they succeed, how long they take, how many sources or creatives they touch, and your client's user agent (for MCP, also the client's name and version). We use this to improve the API. We don't record the values you send.

Endpoints​

MethodPathScopeWhat it does
GET/v1/mereadThe account and scope of your key
GET/v1/limitsreadToday's usage of your daily limits
GET/v1/balancereadYour balance and how long it will last
GET/v1/campaignsreadList campaigns
POST/v1/campaignswriteCreate a campaign
GET/v1/campaigns/{campaign_id}readGet a campaign, including default bid and delivery status
PATCH/v1/campaigns/{campaign_id}writeChange bid, budget, target CPA, audience, schedule or name
POST/v1/campaigns/{campaign_id}/statuswritePause, activate or archive
POST/v1/campaigns/{campaign_id}/clonewriteClone a campaign
GET/v1/campaigns/{campaign_id}/creativesreadList a campaign's creatives
POST/v1/campaigns/{campaign_id}/creativeswriteAdd up to 20 creatives
GET/v1/creatives/{creative_id}readGet a creative
PATCH/v1/creatives/{creative_id}writeEdit a creative
POST/v1/creatives/{creative_id}/statuswritePause, activate or archive
POST/v1/creatives/{creative_id}/clonewriteClone a creative
POST/v1/imageswriteUpload an image or icon
GET/v1/campaigns/{campaign_id}/sourcesreadSource targeting mode, blocked/allowed sources, bid overrides
POST/v1/campaigns/{campaign_id}/sources/bidswriteSet bids for up to 50 sources
POST/v1/campaigns/{campaign_id}/sources/blockwriteBlock sources
POST/v1/campaigns/{campaign_id}/sources/unblockwriteUnblock sources
POST/v1/campaigns/{campaign_id}/sources/allowwriteAllow sources (allow-list campaigns)
POST/v1/campaigns/{campaign_id}/sources/disallowwriteRemove allowed sources

Campaigns​

List Campaigns​

curl -H 'Authorization: Bearer pnk_...' \
'https://ads-api.pushnami.com/v1/campaigns?status=active,paused&search=summer&limit=50'

status accepts active, paused, archived and rejected. The default is active,paused.

Get a Campaign​

curl -H 'Authorization: Bearer pnk_...' https://ads-api.pushnami.com/v1/campaigns/C0001234
{
"id": "C0001234",
"name": "Summer Sweepstakes",
"status": "active",
"delivery_status": "daily_limit_reached",
"created_at": "2026-08-01T14:00:00.000Z",
"updated_at": "2026-09-20T09:12:44.000Z",
"default_bid": 0.25,
"daily_spend_limit": 500,
"target_cpa": 12,
"source_optimization": true,
"source_mode": "block",
"active_creative_count": 4,
"audience": { "country": "US", "platforms": ["MOBILE"], "subscribed_more_than_minutes_ago": 1440 },
"schedule": { "start_date": "2026-08-01T00:00:00.000Z", "end_date": null, "active_hours": [] }
}

status is what you set. delivery_status explains whether the campaign is serving right now:

delivery_statusMeaning
deliveringServing
delivering_with_rejected_creativesServing, but some creatives were rejected
paused / archivedPaused or archived
waiting_for_fundsThe account needs funds
waiting_for_creativesNo active creatives, for example none yet, or all of them pending, draft or paused
all_creatives_rejectedEvery creative was rejected
scheduledThe start date is in the future
ending_soonThe end date is within 48 hours
near_daily_limit / daily_limit_reached85% or 100% of today's spend limit is used
rejectedThe campaign was rejected by review

If the delivery status can't be read at that moment, delivery_status and active_creative_count are left out of the response. Read the campaign again shortly.

Create a Campaign​

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/campaigns \
-d '{
"name": "Fall Promo - Mobile US",
"default_bid": 0.20,
"daily_spend_limit": 250,
"audience": { "country": "US", "platforms": ["MOBILE", "TABLET"] },
"start_date": "2026-10-01T05:00:00Z",
"status": "paused"
}'
FieldRequiredNotes
nameYesUp to 100 characters
audienceYesSee Audience. {} targets everyone.
default_bidYesUSD per click, $0.10 to $25. See Minimum bids.
daily_spend_limitYesAt least $100
target_cpaNoAt least $1. Turns on source optimization.
start_dateNoDefaults to now
end_dateNoOmit for no end date
statusNoactive (default) or paused

A new campaign starts delivering once it has an approved creative and your account has funds. Add creatives next with Create Creatives.

Update a Campaign​

Send only the fields you want to change.

curl -X PATCH -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/campaigns/C0001234 \
-d '{ "default_bid": 0.30, "daily_spend_limit": 400 }'
FieldNotes
nameRename
default_bidNew default bid, at most double the current one
daily_spend_limitA new limit, at least $100 and at most double the current one. Removing the limit is only possible in the dashboard.
target_cpaA number turns source optimization on or changes the target (at most double the current one). null turns it off.
audienceReplaces the whole audience
start_date, end_dateend_date: null removes the end date. Day-parting (active hours) set in the dashboard is kept.

Changes are applied one field at a time. If one fails, the fields before it are already saved and the error lists them in details.applied. Read the campaign again before retrying.

Pause, Activate or Archive​

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/campaigns/C0001234/status -d '{ "status": "paused" }'

status is active, paused or archived. Pausing stops delivery within seconds.

Archiving is permanent

An archived campaign can't be reactivated or edited. Pause it instead if you might need it again.

Clone a Campaign​

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/campaigns/C0001234/clone \
-d '{ "name": "Fall Promo - Desktop", "include_creatives": true }'

name is required. The clone copies the audience, schedule, bid, daily limit, target CPA and source targeting. Send daily_spend_limit to give the clone a different limit (required if the original has none). With include_creatives (the default), active, paused and pending creatives are copied and sent to review. Clones start paused unless you send "status": "active".

The API refuses to clone a campaign that was switched to an allow-list with no sources yet and still enforces its old block-list, because the copy would lose those blocks. Add allowed sources or switch it back to a block-list first.

Audience​

The audience uses the same options as the dashboard's audience form:

FieldValues
countryOne of US, CA, GB, AU, DE, FR, IT, IE, NL, JP, SG, HK, IL, AE
statesUS state codes, for example ["TX", "CA"]. Needs country: "US".
platformsAny of DESKTOP, MOBILE, TABLET, OTHER
subscribed_more_than_minutes_agoOnly subscribers older than this many minutes
subscribed_less_than_minutes_agoOnly subscribers newer than this many minutes (10080 = 7 days)
min_age, max_age13–120
genderM or F. Omit to target both.

When you read a campaign, audience.unsupported_targeting: true means it has targeting these fields can't show, such as a rule that excludes a country, state, platform or gender. That targeting is set in the dashboard and isn't included in the other fields. Sending audience replaces the whole audience, including those rules.

Minimum Bids​

  • $0.10 by default
  • $0.30 when the audience targets subscribers newer than 7 days, or uses age or gender

Creatives​

New and edited creatives go through the usual review process, which usually takes up to 24 hours. They start serving on their own once approved.

Upload Images​

Upload the icon and (optionally) the large image first. PNG, JPEG and GIF are accepted, up to 700 KB.

From a link. This is the simplest option and the best one for AI assistants. Send a public https URL and we download it:

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/images \
-d '{"kind": "icon", "image_url": "https://cdn.example.com/icon.png"}'

The link must be publicly reachable over https on the standard port and must download within 10 seconds. Up to 3 redirects are followed. The file type is read from the file itself. Links to private networks, IP addresses or localhost are refused.

From a file. Send the file as base64 with its content_type. This example uses jq to build the body and pipes it to curl, because a large file can be too long for a single shell argument:

base64 < icon.png | tr -d '\n' \
| jq -Rs '{kind: "icon", content_type: "image/png", data_base64: .}' \
| curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/images -d @-
{ "icon_id": "66f1c2a9e4b0a1b2c3d4e5f6", "url": "https://api.pushnami.com/api/push/icon/id/66f1c2a9e4b0a1b2c3d4e5f6" }

Use "kind": "image" for the large image; the response then has image_id. See Push Notification Specifications for sizes.

Create Creatives​

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/campaigns/C0001234/creatives \
-d '{
"creatives": [
{
"title": "Your fall deal is here",
"message": "Save 30% this week only. Tap to claim.",
"link": "https://example.com/offer?cid=<<conversion_id>>&src={{=data.adsourceid}}",
"icon_id": "66f1c2a9e4b0a1b2c3d4e5f6",
"image_id": "66f1c2b7e4b0a1b2c3d4e5f7",
"button1": "Claim Offer"
}
]
}'
FieldRequired to submitNotes
titleYesUp to 100 characters; 34 or fewer recommended
messageYesUp to 200 characters; 65 or fewer recommended
linkYeshttp(s)://, up to 2,000 characters. Supports tracking values.
icon_idYesFrom Upload Images
image_idNoLarge image
button1, button2NoUp to 25 characters each

Send up to 20 creatives per request. Add "draft": true to save them as drafts instead of submitting; drafts only need one field.

Titles, messages and links can use dynamic variables, such as {{=data.dcity||'Your City'}} or {{#def.date('MMMM')}}. The API accepts the documented forms only: a data. field, a quoted fallback joined with ||, or def.date with an optional format.

Edit a Creative​

curl -X PATCH -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/creatives/C0001234-001 -d '{ "title": "Last chance: 30% off" }'
  • Pending, rejected or draft creatives are updated in place and (re)submitted for review. For a draft, add "submit_for_review": true to submit it.
  • Active or paused creatives get a new version. The original keeps running while the new version is reviewed, and the new version replaces it once approved. The response has new_version_created: true and the new creative's ID. If an edit is already in review, that edit is updated instead of a second one being made.

To clear image_id, button1 or button2, send null.

Pause, Activate or Archive a Creative​

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/creatives/C0001234-001/status -d '{ "status": "paused" }'
  • You can pause an active creative and activate a paused one.
  • Only a paused creative can be activated. Pending, rejected and draft creatives go live when review approves them.
  • Archiving is permanent.

Clone a Creative​

For an A/B test, clone a creative and change one field.

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/creatives/C0001234-001/clone \
-d '{ "title": "Only 3 days left", "campaign_id": "C0001250" }'

campaign_id is optional and defaults to the original's campaign. The clone is submitted for review unless you add "draft": true.

Creative Statuses​

active, paused, pending_review, rejected, draft, archived. Rejected creatives include rejection_reasons and rejection_comment, so you can fix and resubmit them.

Sources​

Get Source Settings​

curl -H 'Authorization: Bearer pnk_...' https://ads-api.pushnami.com/v1/campaigns/C0001234/sources
{
"campaign_id": "C0001234",
"mode": "block",
"blocked_source_ids": ["S0004483", "S0007710"],
"blocked_source_count": 2,
"allowed_source_ids": [],
"allowed_source_count": 0,
"linked_source_list_count": 1,
"bid_overrides": [
{ "source_id": "S0001102", "bid": 0.35, "optimized": false }
],
"bid_override_count": 1,
"truncated": false
}

bid_overrides and bid_override_count are null when the bids can't be read at that moment. That doesn't mean there are no overrides.

mode is block (serve everywhere except blocked sources) or allow (serve only on allowed sources). Change the mode and linked source lists in the dashboard. For per-source performance, use the Spend Report API with source_id.

Set Source Bids​

Set bids for up to 50 sources in one request. A bid can be at most 3× the campaign's default bid.

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/campaigns/C0001234/sources/bids \
-d '{ "source_ids": ["S0001102", "S0001188"], "bid": 0.35 }'
  • "bid": 0.35 sets an override
  • "bid": null goes back to the campaign's default bid
  • "optimize": true hands the sources to source optimization (the campaign needs a target_cpa)

The response lists updated_source_ids and any unknown_source_ids. Source bids can't be changed on an archived campaign.

Block, Unblock, Allow, Disallow​

curl -X POST -H 'Authorization: Bearer pnk_...' -H 'Content-Type: application/json' \
https://ads-api.pushnami.com/v1/campaigns/C0001234/sources/block \
-d '{ "source_ids": ["S0004483"] }'
EndpointCampaign modeEffect
/sources/blockblockStop buying traffic from these sources
/sources/unblockblockStart buying from them again
/sources/allowallowAdd sources to the allow-list
/sources/disallowallowRemove sources from the allow-list

The response lists updated_source_ids and any unknown_source_ids. If the change was saved but some sources aren't in force yet, it also has not_enforced_source_ids and a warning. Check Get Source Settings shortly, and repeat the change if they are still listed. Sources can't be changed on an archived campaign.

Removing the last allowed source

Removing the last allowed source would put the campaign back in block mode with nothing blocked, so it would serve on every source. The API refuses that request with 409 conflict. Pause the campaign instead, or make the change in the dashboard.

Balance​

GET /v1/balance (the get_balance tool over MCP) shows your available balance and how long it will last at your current pace. It's read-only: add funds in the dashboard (card) or by wire (prepay).

curl https://ads-api.pushnami.com/v1/balance -H "Authorization: Bearer $PUSHNAMI_ADS_KEY"
{
"account_id": "62c668500000000000000000",
"payment_type": "prepay",
"available_balance": 5000,
"currency": "USD",
"auto_funding": null,
"average_daily_spend": 1000,
"days_remaining": 5,
"estimated_depletion_date": "2026-09-29T14:00:00.000Z",
"refill_by_date": "2026-09-26T14:00:00.000Z",
"status": "low",
"message": "At the current pace your balance of $5,000.00 lasts about 5 more day(s). Send a wire by Sep 26 so it arrives before the balance runs out.",
"as_of": "2026-09-24T14:00:00.000Z"
}
FieldMeaning
payment_typecard (you add funds by card, optionally with auto-funding) or prepay (you prepay by wire)
auto_fundingCard accounts only: whether auto-funding is on, the balance it refills below, and how much it adds. Card details are never returned.
average_daily_spendAverage over the last 7 full days
days_remaining, estimated_depletion_dateAt the current pace. null when nothing is delivering or there's no recent spend.
refill_by_datePrepay only: the last day to send a wire so it arrives (about 3 days) before the balance runs out
statusok, low, depleted, or unknown when spend couldn't be read
messageWhat to do, in plain language

When status is low:

  • Prepay: the balance lasts 7 days or less at the current pace. At 3 days or less, the message says to wire today.
  • Card without auto-funding: the balance is under $500, or lasts 3 days or less.
  • Card with auto-funding: never low. If the balance runs out anyway, status is depleted, which usually means a top-up failed. Check your payment method.

The balance is refreshed at most every 10 minutes. Pass ?fresh=true to force a new read, at most once a minute. For a daily low-balance alert, poll this once or twice a day and alert on status.

Errors​

Every error has this shape:

{
"error": {
"code": "validation_failed",
"message": "Invalid input for update_campaign.",
"details": [{ "path": "daily_spend_limit", "message": "must be >= 100" }]
}
}
StatuscodeMeaning
400bad_request, validation_failedFix the request. details lists each field.
401unauthorizedMissing, invalid, expired or revoked key
403forbiddenA read key tried to make a change, or API access for the account is suspended
404not_foundNot in your account
409conflictNot allowed in the current state or by a safeguard, for example activating an archived campaign or more than doubling a bid. See Conflicts.
429rate_limitedToo many requests, a daily limit was reached, or an overlapping change is still running. Wait for the Retry-After seconds.
502upstream_errorA Pushnami service didn't respond, or the request took longer than 25 seconds (2 minutes to create or clone a campaign). It may still have completed, so check before retrying.
503unavailableThe API is busy or changes are briefly paused. Wait for Retry-After and retry. Pausing still works.
500internal_errorOur fault. Include request_id when you contact support.

Limits and Safeguards​

These limits cap how much a faulty script or AI assistant can change. Make large or unusual changes in the dashboard, where a person makes them on purpose.

Pausing is never limited. You can always pause a campaign or creative through the API, even when other changes are turned off.

Per Request​

LimitValue
Sources per request (block, unblock, allow, disallow, bids)50, the same as one page in the dashboard
Creatives per request20
Creatives copied by Clone CampaignThe 20 newest

Per Day​

Each account has a daily budget for each kind of change. It's shared by all the account's API keys and resets at 00:00 UTC. Changes you make in the dashboard don't count.

Kind of changeDaily limit
Sources blocked, unblocked, allowed or disallowed1,000 sources
Source bids set, reset or optimized2,500 sources
Campaign updates (bids, budget, target CPA, audience, schedule, name)100
Campaigns created or cloned20
Creatives created or cloned100
Creative edits200
Campaigns and creatives activated50
Campaigns and creatives archived25
Image uploads200

Check what's left with GET /v1/limits (the get_limits tool over MCP):

{
"resets_at": "2026-09-25T00:00:00.000Z",
"writes_enabled": true,
"daily": {
"source_targeting_changes": { "limit": 1000, "used": 150, "remaining": 850 },
"archives": { "limit": 25, "used": 0, "remaining": 25 }
},
"per_request": { "source_ids": 50, "creatives": 20 },
"always_allowed": ["pausing campaigns and creatives"]
}

When a limit is reached, the API answers 429 rate_limited. The response says which limit was hit and has a Retry-After header with the seconds until the reset. For more, make the change in the dashboard or ask your account representative.

Money Settings​

  • API-created campaigns must have a daily spend limit. The API can change the limit but not remove it; only the dashboard can.
  • No big jumps in one change. A campaign's default bid, daily spend limit and target CPA can at most double in a single change. To go higher, raise it in steps or use the dashboard. This catches typos like 2.50 for 0.25.
  • Source bids can be at most 3× the campaign's default bid.

Source Targeting​

  • /sources/disallow won't remove the last allowed source from an allow-list campaign. See Removing the last allowed source.
  • Add "dry_run": true to any source request (block, unblock, allow, disallow, bids) to see which sources would change, with no changes made and none of your daily budget used.

Overlapping Changes​

Some changes run one at a time. If you send a second one while the first is still running, the second gets 429 rate_limited with a short Retry-After. Wait, read the object again, then retry. This applies to:

  • updating the same campaign
  • activating or archiving the same campaign or creative
  • editing the same creative
  • changing the sources of the same campaign (block, unblock, allow, disallow)
  • creating campaigns in the same account
  • creating creatives in the same campaign

Pausing is never held up this way.

Conflicts​

409 conflict means the change isn't allowed right now. Don't retry it unchanged. Besides the cases above, the API returns it when:

  • you activate a campaign or creative while an earlier pause of it may still be finishing. Retry the activation in a minute.
  • you change sources or set source bids on an archived campaign
  • a creative is archived while an edit to it is running. The edit doesn't take effect.
  • you clone a campaign that was switched to an empty allow-list (see Clone a Campaign)

Request Rate​

  • Per account: each request uses part of a per-minute allowance shared by all the account's keys. Reads like list_campaigns use little; get_campaign and changes use more. Normal use, even a busy script, stays well inside it.
  • At once: up to 4 requests can run at the same time per account.
  • Per key: 120 requests per minute.
  • Logins: creating and revoking keys with a username and password is limited to 5 attempts per 15 minutes per username, and 10 per IP address.

When you go over, you get 429 rate_limited. If the API as a whole is busy, or a service it depends on is having trouble, you get 503 unavailable. Both come with a Retry-After header. Wait that many seconds, then retry.

To stay fast:

  • Use GET /v1/campaigns to scan many campaigns, and GET /v1/campaigns/{campaign_id} only for the ones you need in detail. default_bid and delivery_status on a campaign can be up to 30 seconds old.
  • Use the bulk endpoints (per-request limits) instead of one request per item.
  • GET /v1/campaigns/{campaign_id}/sources returns up to 500 bid overrides and 1,000 blocked or allowed sources. It includes the full counts and truncated: true when there are more.

Code Examples​

Python​

import os
import requests

API = "https://ads-api.pushnami.com"
HEADERS = {"Authorization": f"Bearer {os.environ['PUSHNAMI_ADS_API_KEY']}"}

# Pause every active campaign whose name contains "Test".
# Collect every page first: pausing changes the filtered list.
params = {"status": "active", "search": "Test", "limit": 100, "offset": 0}
ids = []
while True:
page = requests.get(f"{API}/v1/campaigns", headers=HEADERS, params=params)
page.raise_for_status()
body = page.json()
ids += [campaign["id"] for campaign in body["data"]]
params["offset"] += params["limit"]
if not body["data"] or params["offset"] >= body["pagination"]["total"]:
break

for campaign_id in ids:
requests.post(f"{API}/v1/campaigns/{campaign_id}/status",
headers=HEADERS, json={"status": "paused"}).raise_for_status()

JavaScript​

const API = 'https://ads-api.pushnami.com';
const headers = {
Authorization: `Bearer ${process.env.PUSHNAMI_ADS_API_KEY}`,
'Content-Type': 'application/json',
};

// Raise the bid on two sources
const res = await fetch(`${API}/v1/campaigns/C0001234/sources/bids`, {
method: 'POST',
headers,
body: JSON.stringify({ source_ids: ['S0001102', 'S0001188'], bid: 0.35 }),
});
console.log(await res.json());

Support​

For API access or issues, contact your Pushnami account representative or email support@pushnami.com.