FAQ

Answers to the questions partners ask most often when integrating the Automated Ads API. If you don't see your question here, reach out to your SymphonyOS representative.

Getting Started

What is the Automated Ads API?

The Automated Ads API lets you launch and manage social media ad campaigns (Meta — Facebook & Instagram — and TikTok) programmatically, on behalf of the brands and artists on your platform. You send a single API call describing the campaign; Symphony handles ad creation, delivery, and optimization.

How is this different from the Ad Box?

  • Automated Ads API — a programmatic REST API you call from your backend. You control the full flow and build your own UI.
  • Ad Box — a white-label, embeddable ad-creation experience (iFrame or custom domain). No engineering required; your users create ads through a hosted UI.

Both run ads through the same Symphony infrastructure. Choose the API for full control, or the Ad Box to go live fast.

Which ad platforms are supported?

Meta (Facebook and Instagram) and TikTok. You choose the platform per campaign with the adPlatform field ("meta" or "tiktok").

Authentication & Access

How do I get an API key?

Apply at symphonyos.co/partnerships. Once approved, you'll be provisioned two keys — a Sandbox key and a Production key. See Get an API Key for details.

How do I authenticate my requests?

Send your key in the x-api-key header on every request:

curl https://api.symphonyos.co/api/sym/v2/api-test \
  -H "x-api-key: YOUR_API_KEY"

What's the difference between the Sandbox and Production keys?

  • Sandbox — for local development and testing. Ads are not set live and no ad spend occurs.
  • Production — real campaigns. Submitted ads are processed and set live with real budget.

Use the same request shapes in both; only the key (and base URL) changes.

Why am I getting a 401 or 403?

  • 401 Unauthorized — the x-api-key header is missing, or the key is not recognized.
  • 403 Forbidden — the key exists but is not active (it may be revoked, suspended, expired, pending, or archived). Contact your representative to reactivate it.

Brands

What is a "brand"?

A brand represents the artist, label, or entity a campaign belongs to. Campaigns, ad-account connections, and analytics are all scoped to a brand. Create one with POST /sym/v2/brands, then pass its id as brandId on subsequent calls.

Do I have to pass a brandId on every call?

No. Each API key has a default brand. If you omit brandId, the call operates against that default brand. Pass brandId explicitly when you manage multiple brands under one key.

Campaigns

How do I create a campaign?

POST /sym/v2/campaigns with adPlatform, an optional brandId, and a campaignInput object describing dates, budget, the promoted link, captions, call-to-action, and targeting. See the Integration Guide and Create campaigns for full worked examples.

Is campaign creation synchronous?

No. The API returns immediately with a campaign record, but submission to Meta/TikTok happens asynchronously in the background. Poll GET /sym/v2/campaigns/:campaignId or register a webhook to track progress.

How do I find the targeting IDs (geographies, interests, languages)?

Use the search endpoints — POST /sym/v2/geography-search, /interest-search, and /language-search. Each takes { adPlatform, query } and returns objects with the id/type/name values you plug directly into campaignInput.targetingConfig.

What call-to-action values are supported?

LEARN_MORE, LISTEN_NOW, and VIEW_NOW.

TikTok note: TikTok ignores the inbound callToAction. The CTA is derived server-side from the campaign type. Only Meta honors the CTA you send.

How does age and gender targeting work?

Set genders to any of ["MALE", "FEMALE"]. For Meta campaigns you must also include minAge and maxAge in targetingConfig (integers between 13 and 65, with minAge <= maxAge).

How is budget interpreted?

budget is the total lifetime budget for the campaign, expressed as a positive number in the currency you provide (e.g. "USD"). Dates are ISO-8601 datetimes.

How do I update, pause, or stop a campaign?

PUT /sym/v2/campaigns/:campaignId accepts any of budget, endDate, and paused. Set paused: true to pause and paused: false to resume. Each applied change fires a campaign.updated webhook event.

What campaign statuses can I expect?

DRAFT, PUBLISHED, SUBMITTED, ACTIVE, STOPPED, FINALIZING, PAUSED, AWAITING_PAYMENT, ERROR, IN_REVIEW, WITH_ISSUES, DENIED, TO_RETRY, FINISHED, and SCHEDULED.

Webhooks

What events can I subscribe to?

campaign.created, campaign.updated, campaign.processing, campaign.completed, and campaign.failed. Register endpoints with POST /sym/v2/webhooks and manage them via the Webhooks guide.

Why is my webhook stuck in pending?

A newly created or updated webhook starts in pending until its first successful delivery. If it stays pending, confirm your endpoint is publicly reachable and returns a 2xx response.

Limits & Errors

What are the rate limits?

The default is 100 requests per minute. Responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Exceeding the limit returns 429 Too Many Requests. Contact your representative if you need a higher limit. See Rate Limits & Error Handling.

What does an error response look like?

Errors use standard HTTP status codes with a JSON body describing the problem:

{
  "success": false,
  "message": "Human-readable summary",
  "error": "Details"
}

Common codes: 400 (validation), 401 (missing/invalid key), 403 (inactive key), 404 (not found), 429 (rate limited), 500 (server error).