Guides

Idempotency

Send an Idempotency-Key so a retried POST never acts twice. It is required on the two calls that spend money.

A network error or a timeout leaves you not knowing whether a POST went through. Send the same request again with the same Idempotency-Key header, and Koast returns the first result instead of acting a second time.

Idempotency-Key: 5f1c2a7e-0d3b-4c39-9a51-2b8e6f0c7d14

Where it applies

OperationIdempotency-Key
POST /v1/brands/{brandId}/launches/{launchId}/publish (launch-campaign)Required
POST /v1/brands/{brandId}/launches/{launchId}/nodes/{nodeId}/live-budget (edit-live-campaign)Required
Every other POSTOptional
GET, PATCH, PUT, DELETENot used

Without the header, the two publishing calls answer 400 idempotency_key_required and do nothing.

How it behaves

  • Same key, same body, within 24 hours: you get the first response back, with the header Idempotent-Replayed: true. Nothing runs again.
  • Same key, different body: 409 idempotency_conflict. A key belongs to one request.
  • Same key while the first request is still running: 409 idempotency_conflict. Wait, then retry.
  • After 24 hours the key is forgotten, and the same key starts a new request.
  • Only responses below 500 are stored. After a 5xx, retrying with the same key runs the request again.
  • Webhook secrets are never replayed. create-webhook-endpoint (POST /v1/webhooks) and rotate-webhook-secret (POST /v1/webhooks/{endpointId}/rotate-secret) answer with a signing secret, which Koast never stores. A retry with the same key and body answers 409 idempotency_conflict and doesn't run again. Read the current secret with GET /v1/webhooks/{endpointId}/secret.
  • If Koast can't reach its idempotency store, the request still runs but isn't recorded, so a retry with the same key isn't recognised as a repeat.
  • Keys are scoped to the API key or OAuth login that sent them. A retry must use the same credential, or it runs as a new request. Use a fresh random value for each new request, such as a UUID. Up to 255 characters.

Example

The first call creates a draft launch:

curl -X POST https://api.koast.ai/v1/brands/1/launches \
  -H "Authorization: Bearer $KOAST_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: guides-evidence-1791521256" \
  -d '{"title":"2026/09/19 | PUR | Vela Daily Greens | CBO"}'
HTTP/1.1 200 OK
Koast-Request-Id: ca523ae6-e474-40e8-a9b5-1fc4a4faca18
RateLimit-Limit: 60
RateLimit-Remaining: 56
RateLimit-Reset: 24
{
  "id": "cmv0hi0hn0001vcam1l3k558m",
  "title": "2026/09/19 | PUR | Vela Daily Greens | CBO",
  "brandId": 1,
  "brandName": "Vela Supplements",
  "accountId": "act_000000000000001"
}

The same call again returns the same launch, and creates nothing:

HTTP/1.1 200 OK
Koast-Request-Id: e19e9f66-8488-4f67-9915-7b6aaff64e33
RateLimit-Limit: 60
RateLimit-Remaining: 55
RateLimit-Reset: 24
Idempotent-Replayed: true
{
  "id": "cmv0hi0hn0001vcam1l3k558m",
  "title": "2026/09/19 | PUR | Vela Daily Greens | CBO",
  "brandId": 1,
  "brandName": "Vela Supplements",
  "accountId": "act_000000000000001"
}

The same key with a different title is refused:

HTTP/1.1 409 Conflict
Koast-Request-Id: 5cd84204-0087-4dbf-963f-061253ec1c35
{
  "error": {
    "code": "idempotency_conflict",
    "message": "This Idempotency-Key was already used with a different request.",
    "details": null,
    "requestId": "5cd84204-0087-4dbf-963f-061253ec1c35"
  }
}

Publishing safely

launch-campaign runs in two steps:

  1. Without "confirm": true, it validates the launch and returns a preview of its campaigns, ad sets, ads and budgets (mode: preview). Nothing is published.
  2. With "confirm": true, it queues the publish and returns mode: publish.

Both steps need an Idempotency-Key. Use a different key for the preview and for the publish, since their bodies differ. If the publish call times out (504 timeout) or the connection drops, send the exact same request with the same key:

  • If the publish finished, you get its result.
  • If it's still running, you get 409 idempotency_conflict. Wait a few seconds and retry.

Never generate a new key to retry a publish. A new key is a new publish.

Publishing also needs the publish scope and a spend ceiling on the key. See Authentication.

In the CLI

koast launch-campaign and koast edit-live-campaign generate a key for you and print it to stderr:

Idempotency-Key: 3b0c7d7e-6a4f-4d55-9f3e-0f8a3c1b2e44

To retry, pass it back with --idempotency-key. Other POST commands send a key only when you pass --idempotency-key.

On this page