Webhook events

launch.completed

A launch published every campaign, ad set and ad.

Event type: launch.completed.

When it fires

A launch published every campaign, ad set and ad.

Envelope

Every event shares these top-level fields. The event-specific fields are under data.

FieldTypeRequiredDescription
idstringYesUnique event id. Deliveries are at-least-once, so dedupe on it.
type"launch.completed"Yes
createdAtstring (date-time)Yes
apiVersion"v1"Yes
organizationIdintegerYes
brandIdinteger | nullYes
accountIdstring | nullYesThe ad account the event concerns.
providerstring | nullYesThe ad platform the event happened on. One of meta, whop.

Data

FieldTypeRequiredDescription
data.launchobjectYes
data.launch.idstringYesThe Koast launch (batch) id.
data.launch.titlestring | nullYes
data.launch.statusstringYesThe launch status after the outcome was decided.
data.launch.startedAtstring (date-time) | nullYes
data.launch.finishedAtstring (date-time) | nullYes
data.campaignsobject[]YesEvery campaign of the launch with its outcome. Empty when truncated is true.
data.campaigns[].koastIdstring | nullYesThe entity id inside Koast.
data.campaigns[].providerIdstring | nullYesThe ad platform's own id. Null when the entity was never created there.
data.campaigns[].namestring | nullYes
data.campaigns[].statusstringYesOne of succeeded, failed, skipped.
data.campaigns[].errorobject | nullYesWhy this entity failed. Null when it succeeded.
data.campaigns[].error.messagestringYesWhat went wrong, as the ad platform or Koast reported it.
data.campaigns[].error.codestring | nullYesThe machine code behind the message when the platform gave one.
data.adSetsobject[]YesEvery ad set of the launch with its outcome. Empty when truncated is true.
data.adSets[].koastIdstring | nullYesThe entity id inside Koast.
data.adSets[].providerIdstring | nullYesThe ad platform's own id. Null when the entity was never created there.
data.adSets[].namestring | nullYes
data.adSets[].statusstringYesOne of succeeded, failed, skipped.
data.adSets[].errorobject | nullYesWhy this entity failed. Null when it succeeded.
data.adSets[].error.messagestringYesWhat went wrong, as the ad platform or Koast reported it.
data.adSets[].error.codestring | nullYesThe machine code behind the message when the platform gave one.
data.adsobject[]YesEvery ad of the launch with its outcome. Empty when truncated is true.
data.ads[].koastIdstring | nullYesThe entity id inside Koast.
data.ads[].providerIdstring | nullYesThe ad platform's own id. Null when the entity was never created there.
data.ads[].namestring | nullYes
data.ads[].statusstringYesOne of succeeded, failed, skipped.
data.ads[].errorobject | nullYesWhy this entity failed. Null when it succeeded.
data.ads[].error.messagestringYesWhat went wrong, as the ad platform or Koast reported it.
data.ads[].error.codestring | nullYesThe machine code behind the message when the platform gave one.
data.errorobject | nullYesThe launch-level failure, when the launch as a whole failed.
data.error.messagestringYesWhat went wrong, as the ad platform or Koast reported it.
data.error.codestring | nullYesThe machine code behind the message when the platform gave one.
data.truncatedbooleanNoPresent and true when the full outcome is too large for one event (over 240 KB, typically 1,000+ ads). The entity arrays are then empty; counts, entityIds and fullObjectPath replace them.
data.countsobjectNoOnly on a truncated event: how many entities of each level succeeded, failed or were skipped.
data.counts.campaignsobjectYes
data.counts.campaigns.totalintegerYes
data.counts.campaigns.succeededintegerYes
data.counts.campaigns.failedintegerYes
data.counts.campaigns.skippedintegerYes
data.counts.adSetsobjectYes
data.counts.adSets.totalintegerYes
data.counts.adSets.succeededintegerYes
data.counts.adSets.failedintegerYes
data.counts.adSets.skippedintegerYes
data.counts.adsobjectYes
data.counts.ads.totalintegerYes
data.counts.ads.succeededintegerYes
data.counts.ads.failedintegerYes
data.counts.ads.skippedintegerYes
data.entityIdsobjectNoOnly on a truncated event: the ids and status of every entity, without names or errors. Omitted when even the ids do not fit.
data.entityIds.campaignsobject[]Yes
data.entityIds.campaigns[].koastIdstring | nullYes
data.entityIds.campaigns[].providerIdstring | nullYes
data.entityIds.campaigns[].accountIdstring | nullYes
data.entityIds.campaigns[].statusstringYesOne of succeeded, failed, skipped.
data.entityIds.adSetsobject[]Yes
data.entityIds.adSets[].koastIdstring | nullYes
data.entityIds.adSets[].providerIdstring | nullYes
data.entityIds.adSets[].accountIdstring | nullYes
data.entityIds.adSets[].statusstringYesOne of succeeded, failed, skipped.
data.entityIds.adsobject[]Yes
data.entityIds.ads[].koastIdstring | nullYes
data.entityIds.ads[].providerIdstring | nullYes
data.entityIds.ads[].accountIdstring | nullYes
data.entityIds.ads[].statusstringYesOne of succeeded, failed, skipped.
data.fullObjectPathstringNoOnly on a truncated event: the API path (GET) of the launch tree, with every campaign, ad set and ad, its platform id and its status.

Example payload

{
  "id": "evt_2xKq7Vb9mN4pR8sT",
  "type": "launch.completed",
  "createdAt": "2026-09-19T14:30:00Z",
  "apiVersion": "v1",
  "organizationId": 1,
  "brandId": 1,
  "accountId": "string",
  "provider": "meta",
  "data": {
    "launch": {
      "id": "string",
      "title": "string",
      "status": "string",
      "startedAt": "2026-09-19T14:30:00Z",
      "finishedAt": "2026-09-19T14:30:00Z"
    },
    "campaigns": [
      {
        "koastId": "string",
        "providerId": "string",
        "name": "string",
        "status": "succeeded",
        "error": {
          "message": "string",
          "code": "string"
        }
      }
    ],
    "adSets": [
      {
        "koastId": "string",
        "providerId": "string",
        "name": "string",
        "status": "succeeded",
        "error": {
          "message": "string",
          "code": "string"
        }
      }
    ],
    "ads": [
      {
        "koastId": "string",
        "providerId": "string",
        "name": "string",
        "status": "succeeded",
        "error": {
          "message": "string",
          "code": "string"
        }
      }
    ],
    "error": {
      "message": "string",
      "code": "string"
    },
    "truncated": true,
    "counts": {
      "campaigns": {
        "total": 1,
        "succeeded": 1,
        "failed": 1,
        "skipped": 1
      },
      "adSets": {
        "total": 1,
        "succeeded": 1,
        "failed": 1,
        "skipped": 1
      },
      "ads": {
        "total": 1,
        "succeeded": 1,
        "failed": 1,
        "skipped": 1
      }
    },
    "entityIds": {
      "campaigns": [
        {
          "koastId": "string",
          "providerId": "string",
          "accountId": "string",
          "status": "succeeded"
        }
      ],
      "adSets": [
        {
          "koastId": "string",
          "providerId": "string",
          "accountId": "string",
          "status": "succeeded"
        }
      ],
      "ads": [
        {
          "koastId": "string",
          "providerId": "string",
          "accountId": "string",
          "status": "succeeded"
        }
      ]
    },
    "fullObjectPath": "string"
  }
}

Delivery headers

HeaderRequiredDescription
webhook-idYesThe delivery id; identical across retries of the same event. Dedupe on the envelope id.
webhook-timestampYesUnix seconds at signing time. Reject deliveries older than 5 minutes.
webhook-signatureYesSpace-separated v1,<base64 HMAC-SHA256> signatures (Standard Webhooks). Two are sent while a rotated secret overlaps.

Acknowledge

Your responseMeaning
2XXReturn any 2xx status to acknowledge the delivery.

Signing, retries and endpoint setup are in the Webhooks guide.

On this page