Webhook events

Signed events we send to your endpoint, following Standard Webhooks.

Verify the signature on the raw body, answer 2xx within 10 seconds and handle each webhook-id once. See Webhooks.

Every event has these fields:

FieldDescription
idThe event id, the same as the webhook-id header.
typeThe event type. Ignore types you don't know.
environmentlive or test, set by the key.
created_atWhen the event happened.
dataThe event's object.

generation.succeeded

Sent when a generation succeeds. data is the generation, with a fresh output.url.

JSON
{
  "id": "evt_4Kq9xT2mVb7Zp1Ls8Hc3Rw",
  "type": "generation.succeeded",
  "environment": "live",
  "created_at": "2026-10-18T10:42:42.901Z",
  "data": {
    "id": "gen_4Kq9xT2mVb7Zp1Ls8Hc3Rw",
    "object": "generation",
    "environment": "live",
    "status": "succeeded",
    "created_at": "2026-10-18T10:42:07.512Z",
    "started_at": "2026-10-18T10:42:09.031Z",
    "completed_at": "2026-10-18T10:42:42.870Z",
    "style_id": "pure-shot",
    "instruction": null,
    "aspect_ratio": "1:1",
    "resolution": "4k",
    "format": "jpeg",
    "metadata": {
      "dish_id": "d_456",
      "vendor_id": "v_1029"
    },
    "credits_charged": 1,
    "output": {
      "url": "https://api.foodshot.ai/v1/files/gen_4Kq9xT2mVb7Zp1Ls8Hc3Rw/image.jpg?exp=1792406563&sig=8fwqDeaHcFOU4b68TzesgCYKN8NG02QP3yMTmmVM9Pc",
      "url_expires_at": "2026-10-19T10:42:43.000Z",
      "available_until": "2026-11-17T10:42:42.870Z",
      "content_type": "image/jpeg",
      "width": 4096,
      "height": 4096,
      "bytes": 8734516
    },
    "error": null,
    "delivery": {
      "status": "pending",
      "attempts": 0,
      "last_status_code": null,
      "last_attempt_at": null
    }
  }
}

generation.failed

Sent when a generation fails. data.error.code says why, and the credit is refunded.

data is the generation, with the same fields as Get generation.

JSON
{
  "id": "evt_rYSdrrqV4cHBg9RlVFImuf",
  "type": "generation.failed",
  "environment": "live",
  "created_at": "2026-10-18T10:40:31.208Z",
  "data": {
    "id": "gen_rYSdrrqV4cHBg9RlVFImuf",
    "object": "generation",
    "environment": "live",
    "status": "failed",
    "created_at": "2026-10-18T10:40:02.117Z",
    "started_at": "2026-10-18T10:40:03.540Z",
    "completed_at": "2026-10-18T10:40:31.176Z",
    "style_id": "white-hero",
    "instruction": null,
    "aspect_ratio": "4:5",
    "resolution": "4k",
    "format": "jpeg",
    "metadata": {
      "dish_id": "d_457"
    },
    "credits_charged": 0,
    "output": null,
    "error": {
      "code": "content_refused",
      "message": "The photo or the instruction was refused by the content checks."
    },
    "delivery": {
      "status": "pending",
      "attempts": 0,
      "last_status_code": null,
      "last_attempt_at": null
    }
  }
}

account.low_balance

Sent when a job takes your live credits below your low-balance threshold, by default 20% of your last plan grant. It is sent again only after credits have been added.

data holds your account id, its environment and your live credits, the same credits object as in Get account.

JSON
{
  "id": "evt_oCtt6VsHVKyRjFPgaJIBwK",
  "type": "account.low_balance",
  "environment": "live",
  "created_at": "2026-10-25T14:03:11.452Z",
  "data": {
    "object": "account",
    "id": "acme-eats",
    "environment": "live",
    "credits": {
      "available": 199,
      "low_balance": true,
      "low_balance_threshold": 200,
      "lots": [
        {
          "id": "lot_9iF8VdFw6H377trtTdF4OH",
          "kind": "plan",
          "remaining": 199,
          "granted": 1000,
          "expires_at": "2026-11-01T00:00:00.000Z"
        }
      ]
    }
  }
}

webhook.test

A test event, sent when you press "Send test event" in the dashboard.

data holds a test message.

JSON
{
  "id": "evt_iBbnS3Z2WrxSId7M6F20KD",
  "type": "webhook.test",
  "environment": "test",
  "created_at": "2026-10-18T09:12:30.104Z",
  "data": {
    "object": "webhook_test",
    "message": "This is a test event from FoodShot."
  }
}

On this page