Docs
APIAPI referenceMetrics

PATCH /v1/projects/:projectId/ads-content/:id

Force-include or force-exclude a creative from ad rotation. The override is one input to the eligibility decision - the facts outrank it.

View as Markdown
PATCH/v1/projects/{projectId}/ads-content/{id}
Phase 1stable
Auth
Bearer
Scope
ads:write

Pins a creative as include or exclude. There is no score gate behind it (the creative score is deprecated, see GET /ads-content). Use exclude to pull a creative off the eligible list immediately. Use include to record an explicit pin; a creative with no override is already eligible by default.

exclude always wins. include does not: it skips no fact, and Layers evaluates the same rules here, on GET /ads-content, on top-performers and at the moment it builds the ad — override → safety review → the source container's ad review → moderator flag → TikTok Spark authorization window → whether the media behind the creative still exists. A creative whose eligibility.reason is safety_failed, flagged, spark_authorization_not_live, spark_window_unknown or source_unavailable stays ineligible whatever the override says, and the response below reports that.

This is the only ads-content mutation available today. Everything else about the creative - paid performance, promotions - is derived. The override field is the single human-writable lever.

Path
  • projectId
    string (UUID)required
    Project containing the creative.
  • id
    stringrequired
    adsContentId - the prefixed adc_<UUID> value returned by GET /ads-content. The bare UUID is also accepted.
Body
  • override
    string | nullrequired
    Set the override. null clears it; the creative is then eligible by default.
    One of: include, exclude,
  • note
    stringoptional
    Short context saved alongside the override. Visible in the audit log; max 280 chars.

Example request

curl -X PATCH https://api.layers.com/v1/projects/prj_254a4ce1-f4ca-42b1-9e36-17ca45ef3d39/ads-content/adc_6f5d4c3b-2a19-4e87-b0c5-1d2e3f4a5b6c \
  -H "Authorization: Bearer lp_..." \
  -H "Content-Type: application/json" \
  -d '{ "override": "exclude", "note": "Legal flagged the background music" }'
const res = await fetch(
  `https://api.layers.com/v1/projects/${projectId}/ads-content/${adsContentId}`,
  {
    method: "PATCH",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ override: "exclude", note: "Legal flagged background music" }),
  },
);
const updated = await res.json();
import httpx

r = httpx.patch(
    f"https://api.layers.com/v1/projects/{project_id}/ads-content/{ads_content_id}",
    headers={"Authorization": f"Bearer {api_key}"},
    json={"override": "exclude", "note": "Legal flagged background music"},
)
updated = r.json()

Response

200OK - returns the updated ads-content item.
{
  "adsContentId": "adc_6f5d4c3b-2a19-4e87-b0c5-1d2e3f4a5b6c",
  "sourceType": "content_container",
  "sourceId": "cnt_9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d",
  "platformPostId": null,
  "scoringPool": "generated",
  "organicScore": 0,
  "organicPerformance": null,
  "adPerformance": null,
  "scoredAt": "2026-04-18T12:00:00Z",
  "scoringVersion": 3,
  "eligibility": { "isEligible": false, "reason": "excluded by override" },
  "override": "exclude",
  "overrideNote": "Legal flagged background music",
  "overrideSetBy": "api_key",
  "overrideSetAt": "2026-04-18T19:22:05Z",
  "activePromotions": []
}
400Invalid override value or empty body.
{
  "error": {
    "code": "VALIDATION",
    "message": "Invalid patch body.",
    "requestId": "req_..."
  }
}
404Ads-content item not found.

What override does

override is the eligibility decision in every place Layers picks creatives to promote:

  • "include" - an explicit pin, recorded and honoured only when every fact already allows the creative to run. It does not clear a safety failure, a moderator flag, a failed container ad review, a Spark authorization that can no longer launch, or missing source media.
  • "exclude" - ineligible. Use this to retire a creative from future ad selection. Ads currently running against it are not paused - ad pause decisions are made from live performance, not from override. Pause them in the platform's ad manager.
  • null - clears the override. The creative is eligible by default; eligibility.reason reads eligible by default; no override set.

Notes

  • Idempotent: PATCHing the same override twice is a no-op with respect to downstream selection.
  • :id is the adsContentId the list endpoint returns, in its prefixed adc_<UUID> form. Pass it back exactly as received; the bare UUID is also accepted, per the tolerance rule.
  • overrideSetBy stores the API key prefix and the api_key id that made the change ("<prefix> (<api_key_id>)"). Audit who-did-what via GET /v1/audit with subjectType=ads_content.
  • Override does not change any other field. Clearing the override returns the creative to the default state as if you had never touched it - eligible, unless one of the facts above refuses it. organicScore is deprecated and always 0.
  • Excluding a creative on one platform excludes it across all platforms. There is no per-platform override.

See also

On this page