siliconrelay.com

Managing creatives over the API

List, upload, replace and remove a campaign's ads from a script, and the one endpoint that will quietly reset your settings if you use it for that.


A campaign can hold several ads at once, and each one has its own id, its own review, and its own numbers. From a script you can list them, add more, swap one out, and take one down, the same four things the campaign page's ad cards do, with the same rules behind them. Your API key already knows which account you are. See Using the API if you haven't minted one yet.

Everything below assumes $KEY holds your key and $CID holds a campaign id (from GET /api/v1/campaigns).

See what a campaign is running

curl -s -H "Authorization: Bearer $KEY" \
  "https://siliconrelay.com/api/v1/campaigns/$CID/creatives"

You get one entry per live ad, in a stable but arbitrary order, the same one your campaign page shows. Sort on created_at if you want them oldest-first. Each carries:

  • id: the ad's id. This is what the other three calls take, and what per-ad reporting rows carry, so it's the field to store.
  • size: the ad size the file was filed under (300×250), and pixel_scale, either 1 or 2 when you uploaded a double-resolution file for sharp screens.
  • status: pending while it's in review, then approved or rejected. A rejected ad carries reject_reason.
  • draft: a replacement you've queued for this ad, still awaiting review. Present only when there is one.

The same list is also included in GET /api/v1/campaigns/$CID under creatives, if you're already fetching the campaign.

Add ads to a campaign

curl -s -H "Authorization: Bearer $KEY" \
  -F banners=@wide.png -F banners=@square.png \
  "https://siliconrelay.com/api/v1/campaigns/$CID/creatives"

Send as many files as you like in one request (up to the 20-ad limit per campaign). We read each image's size from the image itself, so there's nothing to declare. New ads start in review. Everything already approved on the campaign keeps running while they wait.

Files are judged one at a time. The response has an added list and a rejected list, so a single bad file never throws away the good ones:

{
  "added": [{"id": "3a8c1f2e-…", "size": "300×250", "status": "pending", "…": "…"}],
  "rejected": ["square.png is 500×500, which isn't one of our ad sizes — nearest accepted: 336×280, 300×250, 320×100 (upload at exactly one of those, or exactly double for Retina)."]
}

If nothing was accepted you get a 422 carrying those same messages. See Banner sizes for what we accept.

Use this endpoint, not the campaign update, to add art. POST /api/v1/campaigns/$CID is the whole edit form: any field you leave out is treated as blank and reset, your daily cap, flight dates and targeting included. This endpoint touches nothing but the ads.

Swap one ad's art

curl -s -H "Authorization: Bearer $KEY" -F banners=@fixed.png \
  "https://siliconrelay.com/api/v1/campaigns/$CID/creatives/$AD/replace"

One file, one ad. What happens next depends on where that ad stands:

  • It's approved and running. Your new file is queued as a revision and goes to review. The approved art keeps serving until the revision is approved. The response is the queued revision, a new id with status: "pending". (Replacing again just swaps the queued file, and you never end up with two waiting.)
  • It's pending or rejected. There's nothing approved to protect, so the file replaces it directly and the ad returns to review under the same id.

The click destination is a campaign-level setting, so a replace never changes where the ad points.

Take an ad down

curl -s -H "Authorization: Bearer $KEY" -X POST \
  "https://siliconrelay.com/api/v1/campaigns/$CID/creatives/$AD/remove"

The ad goes, along with any revision you had queued for it. If it was the campaign's last approved ad, the campaign is paused, because it would have nothing left to show. Both the removal and the pause appear in the campaign's history.

Removing an ad never erases its past numbers. Per-ad reporting keeps them and labels the row as a removed ad.

Match reporting rows back to ads

Per-ad numbers come from the report, not from the list above, because one place produces every number, so the two can never disagree:

curl -s -H "Authorization: Bearer $KEY" \
  "https://siliconrelay.com/api/v1/report?by=creative&from=2026-07-01&to=2026-07-27"

Each row carries a creative_id that matches an id from the creatives list, and that's your join. Key on it rather than on the row's human label, which is written for people to read (its short id is cut off). Add .csv for the spreadsheet version and the id is there as a creative_id column, and the raw event export (/api/v1/events.csv) carries one too, so you can attribute individual impressions and clicks to the exact ad that served them.

Things worth knowing

  • No approval shortcut. Ads uploaded through the API enter the same review queue as ads uploaded in the browser. There is no way around it, for anyone.
  • Banners only. Text and HTML5 ads are single-ad formats, edited through the campaign form. These endpoints work with image ads.
  • Ids you don't own read as "not found." Another account's ad, an ad from a different campaign, and a queued revision's id all answer 404, the same answer as an id that doesn't exist, so nothing about other accounts leaks.