Browse API docs

Advertising

Advertising is currently in limited beta and is not available to every account. When access has been enabled for an account, a read token can inspect its Meta connection and campaign state; campaign changes require a Read + Write token and the same owner-confirmation rules as the dashboard. Requests from accounts without access return 403 Forbidden with an errors.base message. Personal co-organizer tokens cannot use these endpoints.

Meta bills the organizer’s own ad account; Usetix never funds ads. Starting, resuming and raising a budget spend money, so they take the preview_id of the exact terms you showed the person deciding: if the campaign changed since, Usetix answers 422. An account write token counts as the owner for these steps.

Starting, pausing, resuming and budget changes are queued. A 200 or 201 means Usetix accepted the work, not that Meta has finished it. Read the campaign again for status, budget, last_error_code and last_error_message.

Method URL Purpose
GET /admin/advertising The Meta connection and every campaign of the account
GET /admin/events/:slug/promotions One event’s campaigns
GET /admin/events/:slug/promotions/:id One campaign with its results
POST /admin/events/:slug/promotions Propose a draft; 201
PATCH /admin/events/:slug/promotions/:id Change a draft
DELETE /admin/events/:slug/promotions/:id Delete a campaign Meta never received, or one Meta holds paused; 204
POST /admin/events/:slug/promotions/:id/approval Start a draft (or retry a failed start)
PATCH /admin/events/:slug/promotions/:id/budget Change a running campaign’s budget
POST /admin/events/:slug/promotions/:id/pause Pause
DELETE /admin/events/:slug/promotions/:id/pause Resume
POST /admin/events/:slug/promotions/:id/synchronization Fetch status and results from Meta again
DELETE /admin/events/:slug/promotions/:id/recommendation Hide the daily review’s suggestion

:id is the campaign’s public ID, not a database number.

GET /admin/advertising

Returns the account’s Meta connection summary and a cursor-paginated list of campaigns, newest first.

curl -H "Authorization: Bearer your-token-here" \
  -H "Accept: application/json" \
  "https://app.usetix.io/admin/advertising?limit=50"

Query parameters:

Parameter Description
limit Campaigns per page, from 1 to 100. Defaults to 50.
page Opaque cursor from the previous response’s pagination.next_page value or Link header.

Response:

{
  "connection": {
    "provider": "meta",
    "status": "ready",
    "configured": true,
    "ad_account_name": "Usetix Ads",
    "page_name": "Usetix Club",
    "instagram_username": "usetixclub",
    "conversion_tracking_enabled": true,
    "organic_publishing_enabled": true
  },
  "advertising_campaigns": [
    {
      "id": "V3x7Kp9Q",
      "event_slug": "summer-showcase",
      "event_title": "Summer Showcase",
      "name": "Summer Showcase · Meta",
      "status": "active",
      "objective": "sales",
      "autonomy_mode": "manual",
      "budget": { "amount": "20.00", "currency": "EUR" },
      "budget_period": "daily",
      "total_budget": { "amount": "240.00", "currency": "EUR" },
      "spent": { "amount": "118.42", "currency": "EUR" },
      "starts_at": "2026-08-20T10:00:00Z",
      "ends_at": "2026-09-01T18:00:00Z",
      "desired_active": true,
      "recommendation": null,
      "last_error_code": null,
      "last_error_message": null,
      "creatives": [],
      "created_at": "2026-08-19T09:00:00Z",
      "updated_at": "2026-08-29T12:00:00Z"
    }
  ],
  "pagination": {
    "total_count": 12,
    "limit": 50,
    "next_page": null
  }
}

connection is null until Meta has been connected. Connection status is one of pending, ready, degraded, expired, or revoked. Each campaign carries the campaign fields; the example leaves some out.

The response sends X-Total-Count with the total campaign count. When another page exists, the Link header contains the full next URL with rel="next"; clients should follow that URL without parsing or modifying the cursor. Invalid cursors and limits return 400 Bad Request with an error string.

GET /admin/events/:slug/promotions

Lists one event’s campaigns, newest first: { "event": { "id", "slug", "title" }, "advertising_campaigns": [ ... ] }, each with the campaign fields.

GET /admin/events/:slug/promotions/:id

Returns one campaign with the campaign fields and its results.

curl -H "Authorization: Bearer your-token-here" \
  -H "Accept: application/json" \
  https://app.usetix.io/admin/events/summer-showcase/promotions/V3x7Kp9Q

POST /admin/events/:slug/promotions

Proposes a draft: name, run, audience around the venue, placements and ad copy. Nothing is created at Meta and nothing is spent. The account needs a configured Meta connection; to start, the ad needs the event’s picture, a video or a Reel.

curl -X POST \
  -H "Authorization: Bearer your-token-here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"advertising_campaign": {"budget": "20.00", "budget_period": "daily", "days": 14, "audience_hint": "People looking for a Friday night out"}}' \
  https://app.usetix.io/admin/events/summer-showcase/promotions

Body parameters:

Field Required Notes
budget yes In the ad account’s currency, as a decimal string. An amount a day with budget_period daily, else the total for the whole run. At least 5.00.
budget_period no daily: Meta spends the amount a day on average and may spend up to 75% more on a single day, keeping each week within seven days’ worth. lifetime (the default): a hard total for the whole run.
days no Runs the campaign over the last this many days before the event, ending when ticket sales end or the event starts, whichever is first. Without it the run starts now.
audience_hint no A short description of the intended audience. Usetix starts near the venue and never infers sensitive traits.
autonomy_mode no manual (the default) or guarded. Guarded lets Usetix pause, resume and lower the budget on its own; it never raises the budget or extends the run.
use_ai no true queues an improvement of copy and audience. Read the campaign again until its creatives change.
media_source no event_image (the default), video with the file in video (MP4 or MOV, sent as multipart/form-data), or instagram_post with a Reel of the connected Instagram account in source_instagram_media_id. A Reel runs on Instagram’s placements only.

The dashboard suggests an amount a day and a run from the ticket price, the tickets left and what a sold ticket cost in the account’s earlier campaigns.

Response: 201 Created with the campaign and its results, and a Location header. 422 when Meta is not connected, the event is too close to its start or sales end, or a field is invalid.

PATCH /admin/events/:slug/promotions/:id

Changes a draft. Once started, a campaign’s terms stay as they were approved; change a running campaign’s amount through its budget.

curl -X PATCH \
  -H "Authorization: Bearer your-token-here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"advertising_campaign": {"budget": "250.00", "budget_period": "lifetime"}}' \
  https://app.usetix.io/admin/events/summer-showcase/promotions/V3x7Kp9Q

Body parameters (all optional): name, budget, budget_period, starts_at, ends_at, autonomy_mode, audience (age_min, age_max, summary, location.city, location.radius_km), placements, creatives_attributes (id, primary_text, headline, description, media_source, video, source_instagram_media_id).

Datetimes without an offset are read in the event’s time zone. creatives_attributes.id is the creative’s id from GET. A city is looked up at Meta; where several places share a name, the one near the venue’s postal code is taken, and the campaign shows Meta’s match before it starts.

Response: 200 OK with the campaign. 422 when the campaign is not a draft or a field is invalid.

DELETE /admin/events/:slug/promotions/:id

Deletes a campaign Meta never received (a draft, or one that failed or was paused before Meta created it) or one whose pause Meta confirmed. A paused one is deleted at Meta first, where Ads Manager keeps its figures; Usetix drops its results with it. Owners, managers and write tokens may delete.

curl -X DELETE \
  -H "Authorization: Bearer your-token-here" \
  -H "Accept: application/json" \
  https://app.usetix.io/admin/events/summer-showcase/promotions/V3x7Kp9Q

Response: 204 No Content. 422 while the campaign runs at Meta, is on its way there, or Meta did not confirm the deletion; pause it first.

POST /admin/events/:slug/promotions/:id/approval

Starts the exact current draft and queues its publication to Meta. This lets Meta spend the budget.

curl -X POST \
  -H "Authorization: Bearer your-token-here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"preview_id": "0f1e2d3c4b5a69788796a5b4c3d2e1f0..."}' \
  https://app.usetix.io/admin/events/summer-showcase/promotions/V3x7Kp9Q/approval

preview_id is the one from GET. When sent and the draft changed since, Usetix returns 422.

Response: 200 OK with the campaign. status becomes approved and then moves through publishing, in_review, scheduled and active as Meta reports back. The same endpoint retries a failed start. A manager’s session gets 403.

PATCH /admin/events/:slug/promotions/:id/budget

Changes the budget of a campaign Meta runs or holds paused. Meta keeps an ad set’s kind of budget, so only the amount changes: an amount a day stays an amount a day.

curl -X PATCH \
  -H "Authorization: Bearer your-token-here" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"budget": "30.00"}' \
  https://app.usetix.io/admin/events/summer-showcase/promotions/V3x7Kp9Q/budget

Body parameters:

Field Required Notes
budget yes The new amount, a day or in total like the campaign’s budget_period. At least 5.00; a total must stay above what is already spent.
preview_id for a higher amount The preview_id Usetix answered for this amount.

A lower amount goes ahead at once. A higher one is confirmed like a start: without preview_id, Usetix answers 422 with the ID for exactly this amount and the campaign as it is now:

{
  "errors": { "base": ["Confirm the higher budget with its preview_id."] },
  "preview_id": "9a8b7c6d5e4f30211203f4e5d6c7b8a9..."
}

Show the new amount, then send the same budget again with that preview_id. Raising needs the owner or an account write token; a manager’s session gets 422.

Response: 200 OK with the campaign. budget changes once Meta has taken the new amount; if Meta refuses, the old one stays and last_error_message says why. 422 when the campaign is not at Meta, has ended or failed, or the amount is not allowed.

POST /admin/events/:slug/promotions/:id/pause

Queues a pause. Owners, managers and write tokens may pause. desired_active turns false at once; delivery stops when Meta confirms.

Response: 200 OK with the campaign.

DELETE /admin/events/:slug/promotions/:id/pause

Resumes a paused campaign with its unchanged terms. Same owner and preview_id rules as a start.

Response: 200 OK with the campaign. 422 when the campaign is not paused, has ended, or the event no longer sells tickets.

POST /admin/events/:slug/promotions/:id/synchronization

Queues a fresh read of the campaign’s status and results from Meta.

Response: 200 OK with the last known campaign and results. Read it again shortly for the new figures.

Daily review

Every morning Usetix reviews each campaign running at Meta and stores a suggestion in recommendation: keep it, raise or lower the budget, or pause. Fixed rules weigh what the campaign spent against the tickets it sold and the ticket price; when the account has AI, the AI weighs the same figures within those rules and explains them in plain words. Nothing changes while Meta still learns (the first two days, or less than two days’ budget spent), and for three days after a budget change only a pause is suggested.

Raising always stays a suggestion for the owner: send it as a budget change. With autonomy_mode guarded, Usetix lowers the budget or pauses on its own where the rules call for it, and the suggestion’s status becomes autopilot.

{
  "action": "lower_budget",
  "status": "open",
  "reason": "A sold ticket currently costs EUR 30,00 in ads, more than the ticket itself (EUR 20,00). With less budget the cost usually drops.",
  "budget": { "amount": "12.00", "currency": "EUR" },
  "reviewed_at": "2026-10-14T07:30:12Z"
}
Field Notes
action keep, raise_budget, lower_budget or pause.
status info (keep), open (a step to take), applied (someone took it), autopilot (guarded autopilot took it) or dismissed.
reason Plain words in the account’s language.
budget The suggested amount for raise_budget and lower_budget, a day or in total like the campaign; otherwise null.
reviewed_at When the review ran, ISO 8601 UTC.

recommendation is null until the first review. DELETE /admin/events/:slug/promotions/:id/recommendation hides the suggestion (status dismissed) until the review suggests something else, and returns the campaign.

Campaign fields

Field Type Notes
id string Public ID for URLs.
event_slug / event_title string  
name string  
status string draft, approved, publishing, in_review, scheduled, active, paused, completed, rejected or failed.
objective string sales or traffic.
autonomy_mode string manual or guarded.
budget money The amount a day or the total, as budget_period says.
budget_period string daily or lifetime.
total_budget money What the run comes to: the total itself, or the amount a day on every day of the run.
spent money What Meta reports as spent.
cost_per_click money or null Spend divided by link clicks, as Ads Manager shows it.
starts_at / ends_at string ISO 8601 UTC. The run ends no later than ticket sales or the event start.
audience object Ages 18 to 65, a summary, and a location with country and city or coordinates and a radius of 1 to 80 km.
placements string[] From facebook_feed, facebook_stories, facebook_reels, instagram_feed, instagram_stories and instagram_reels. Without a connected Instagram account, Facebook’s only.
beneficiary_name / payer_name string Named for EU ad transparency.
preview_id string Identifies the current spend terms. Send it back to start or resume.
desired_active boolean Whether Usetix wants the campaign to deliver.
recommendation object or null The daily review’s suggestion.
last_error_code / last_error_message string or null The last refusal from Meta, in Meta’s own words where it gives them.
creatives array Each ad: id, name, primary_text, headline, description, destination_url, position, generated_by_ai, media_source, video_attached, instagram_media_id, instagram_permalink.
created_at / updated_at string ISO 8601 UTC.

Results

A single campaign (GET, and the answers of the endpoints that change it) also includes:

Field Notes
provider.spend What Meta reports as spent (money).
provider.impressions / reach / clicks / landing_page_views / purchases Integers.
provider.purchase_value Purchase value Meta attributes to the ads (money).
provider.roas Return on ad spend, or null while nothing is spent.
usetix.orders Orders whose first visit came through this campaign.
usetix.revenue Net revenue of those orders (money).

Meta’s attribution and Usetix’s first-visit orders can differ; treat them as two measurements.