Skip to main content
Once a campaign is running, the API lets you adjust its daily budget, reallocate geographic tiers, toggle auto-renew, and stop delivery. All management endpoints require the campaigns:write scope and work on wallet-funded campaigns only.

Which campaigns can you manage?

Campaign list and detail responses include a generation field: Calling a management endpoint on a non-generation-3 campaign returns 400 invalid_request (for example, “Stopping is only supported for wallet campaigns.”).
TypeScript: soundlink.campaigns.increaseBudget / decreaseBudget / tiers / stop — see TypeScript SDK.
Stop, budget, and auto-renew endpoints require the same Idempotency-Key header as campaign creation: unique string up to 255 characters, honored for 24 hours, same key + same body replays the original response.

Increase budget

POST /v1/campaigns/{campaignId}/budget/increase Adds budget using credits already in your wallet — there is no new card payment.
  • amount is the total USD debit for the current cycle. With mode: next_renewal you may send amount: 0 together with targetDailyBudget to set an absolute next-cycle daily budget.
  • The wallet is debited whenever the current cycle is increased. If the balance is too low, you get 402 insufficient_credit with details.available and details.required.
The response returns the wallet balance after the debit:

Decrease budget

POST /v1/campaigns/{campaignId}/budget/decrease Lowers the campaign’s daily budget to targetDailyBudget and refunds unused budget to your wallet.
Rules (violations return 400 invalid_request):
  • targetDailyBudget must be at least $10/day and lower than the current daily budget
  • More than 3 days must remain in the current billing cycle
  • Modes: current_cycle or current_and_renewals (default) — next_renewal is not supported for decreases
A success response returns accepted: true. The refund of unused budget is applied to your wallet asynchronously after acceptance — it may take a moment to appear in your balance.

Update geographic tiers

GET /v1/campaigns/{campaignId}/tiers (requires campaigns:read) returns the current allocation and each tier’s learningStatus (LEARNING, FAIL, SUCCESS, or null):
PATCH /v1/campaigns/{campaignId}/tiers enables/disables tiers and reallocates budget shares:
Request rules:
  • Include all of the campaign’s tiers in items — not just the ones you change
  • newAllocationPercent values must sum to exactly 100
  • At least one tier must have isEnabled: true
  • acknowledgeLearningWarning is optional. Omit it or send false to leave the warning unacknowledged. Only true acknowledges it.
Within 72 hours of the latest tier or country targeting update, PATCH returns 409 learning_edit_ack_required when a tier that is active before the update has learningStatus LEARNING or FAIL. details.tierIds lists those tiers. Send the same body with acknowledgeLearningWarning: true to continue. SUCCESS, null, and updates outside that window do not need acknowledgement. A body that matches the current tiers is accepted and does not change them.

Toggle auto-renew

PUT /v1/campaigns/{campaignId}/auto-renew Turns auto-renew on or off. Wallet campaigns only. Allowed when status is active or renew_failed.
Expected (200):
A matching stored value succeeds with no change.

Read wallet balance

GET /v1/wallet · scope wallet:read Returns the organization wallet. available is what POST /v1/campaigns checks before reserving. reserved is the sum of active reservations. Existing keys do not include wallet:read until that scope is granted.
Expected (200):
See GET /v1/wallet for the full response.

Stop a campaign

POST /v1/campaigns/{campaignId}/stop Stops delivery and refunds the unspent budget to your wallet.
Expected (200):
These statuses accept stop and return stopped: active, inactive, restarting, restart_failed, renew_failed, and renew_awaiting_charge. stopped and ended succeed without changing status. The response status stays stopped or ended, and a second stop does not refund again. creating and renewing return 400 invalid_request. Retry after the campaign leaves that status. Stopped campaigns cannot be restarted via the API — create a new campaign instead.

Activity

GET /v1/campaigns/{campaignId}/activity POST /v1/campaigns/activity/batch Requires campaigns:read. Returns a page of creative adds, creative pause/resume (user request or Meta sync), budget changes, tier updates, country updates, playlist redirect heals, and auto-renew changes. Each item has event_type, timestamp, and summary. Replacing a creative shows up as a pause of the old creative plus CAMPAIGN_AD_CREATIVES_ADDED for the new one. The list does not include campaign creation. Fee amounts, Stripe ids, and internal file URIs are left out. Apply any waiting rule, such as 72 hours after a change, on your side. This endpoint does not block the next change. startDate keeps events at or after that date (YYYY-MM-DD, from 00:00:00Z) or ISO-8601 timestamp. Omit it to page the full history. page defaults to 1. pageSize defaults to 20 and maxes at 100.
The batch route returns one activity page per authorized campaign (data.items[].campaignId, items, pagination). Shared page, pageSize, and startDate apply to every ID. Up to 50 campaignIds, one rate-limit unit. Unauthorized or unknown IDs are omitted. Batch reads must be enabled for your organization — otherwise the route returns 404.

Common management errors

See Errors for the full list.

Next

Creating campaigns · Campaign metrics · Credit wallet