Docs
APIAPI referenceAds

DELETE /v1/projects/:projectId/ads/:platform/campaigns/:campaignId

Soft-delete a campaign on the platform.

View as Markdown
DELETE/v1/projects/:projectId/ads/{platform}/campaigns/:campaignId
Phase 1stable
Auth
Bearer
Scope
ads:write:lifecycle

Marks the campaign deleted on the platform (Meta DELETED, TikTok DELETE, Apple REMOVED). Most platforms preserve historical metrics for the deleted campaign indefinitely; Layers' GET …/campaigns?status=deleted continues to return it.

Same shape applies to adsets and ads:

  • DELETE …/adsets/:adsetId
  • DELETE …/ads/:adId

Authority

Delete is gated by the structural axis. With structural: "off" (the default for manual campaigns), every delete is denied.

Request

curl -X DELETE https://api.layers.com/v1/projects/$PROJECT_ID/ads/meta/campaigns/$CAMPAIGN_ID \
  -H "Authorization: Bearer $LAYERS_API_KEY"

Response

200 with {entityId, platform, partnerStatus, platformStatus, verdictId, occurredAt} — the same envelope the pause / resume endpoints return. partnerStatus is deleted; platformStatus is the platform-native terminal Layers translated to (DELETED on Meta, DELETE on TikTok, REMOVED on Apple).

The response is an acknowledgement, not a completion: the platform write is dispatched asynchronously through the gate, and settlement surfaces through the ads.write.executed / ads.write.denied webhooks. verdictId is the audit id for this dispatch, and is null when no audit row was written.

Repeating a delete

Delete is idempotent, as Idempotency promises for every DELETE: send it twice and the second call returns the same 200 envelope the first did. One entity has one deletion, so the repeat is answered from the first one rather than sent to the platform again — whether that first delete has already been carried out or is still on its way.

The one case we can't answer that way is a first delete that reached the platform and whose outcome we can't establish. We don't send a second one and we don't pretend it's done; you get a CONFLICT carrying details.reason: "delete_outcome_unconfirmed". Check the platform's own console for the entity, then reconcile. Retrying the call won't change the answer.

Errors

CodeWhen
AUTHORITY_DENIEDstructural axis is off.
FORBIDDEN_SCOPEKey lacks ads:write:lifecycle.
CONFLICTdetails.reason: "delete_outcome_unconfirmed" — an earlier delete of this entity reached the platform and we can't confirm what it did. Nothing was sent a second time. Not retryable; check the platform console.

See also

On this page