Webhooks

Event catalog

The events you can subscribe to and the payloads they deliver.

The v1 catalog is deliberately small and AI-only. Every event listed here is emitted at a real state change in the platform — the publisher drops anything not in the catalog, so the console never advertises an event that never fires. Each event is delivered inside a signed webhook envelope; this page documents the events themselves and the data each one carries.

Events

These are the event types you can subscribe an endpoint to today.

Event Scope family Fires when
imagine.completed user own-data-only An image-generation job you own finishes successfully.

One event today is by design, not a placeholder. The catalog widens over time as more domain events are teed into the webhook platform. Build your consumer to ignore event type values it does not recognize so new events are additive, never breaking.

Scope families

Each event belongs to a scope family that governs how a subscription may be scoped and how fan-out authorizes delivery. imagine.completed is a user event:

See Scopes for how scope families relate to the OAuth-style scopes granted to your API keys, and Webhooks overview for the subscription model.

The envelope

Every event — regardless of type — is delivered as the same top-level JSON envelope. The event-specific body lives under data. The envelope pins an api_version so a payload-shape change is a version bump you can detect, not a silent break.

Field Type Description
id string Unique event id (a ULID). Stable across delivery retries — use it as your idempotency key when processing.
type string The event name from the catalog, e.g. imagine.completed.
api_version string Date-stamped payload-contract version. Currently 2026-07-12 for every event.
created_at integer Unix epoch time in seconds when the event was recorded.
scope string "user" or "guild", reflecting the event's scope family. Always "user" for imagine.completed.
resource_id string The id of the resource that changed. For imagine.completed this equals the data.job_id. Omitted when there is no subject resource.
data object The event-specific payload, documented per event below.

The envelope you receive from a real delivery is byte-identical in shape to the one sent by the console's test ping, so you can validate your handler against a test event with the same code path. Signature headers and verification are covered in Signature verification.

imagine.completed

Emitted when an image-generation (“imagine”) job you own reaches the SUCCEEDED state. The payload carries your own job's output and metadata — nothing else.

Data fields

Field Type Always present Description
job_id string Yes The image job's unique id (a UUID). Matches the envelope resource_id. Because it is also the event's idempotency key, a single job produces at most one imagine.completed event.
status string Yes Always "SUCCEEDED". Only successful jobs deliver this event (see below).
output_url string Yes Absolute HTTPS URL to the rendered image, e.g. https://exe.krallo.com/img/ai/<uuid>.png.
provider_used string When set The provider label that produced the final image, e.g. fal_seedream or grok. A coarse label only — no model, cost, or routing internals.
mode string When set The generation mode, lower-cased: text_to_image, image_to_image, or inpaint.
width integer Yes Output width in pixels (after post-processing).
height integer Yes Output height in pixels (after post-processing).

Example event

The full delivered body — envelope plus data:

json
{
  "id": "01J8Z9K3M4P5Q6R7S8T9V0W1X2",
  "type": "imagine.completed",
  "api_version": "2026-07-12",
  "created_at": 1752566400,
  "scope": "user",
  "resource_id": "6f3a2c1e-9b0d-4e21-8a77-1c2d3e4f5a6b",
  "data": {
    "job_id": "6f3a2c1e-9b0d-4e21-8a77-1c2d3e4f5a6b",
    "status": "SUCCEEDED",
    "output_url": "https://exe.krallo.com/img/ai/2b7c9d1e-0f34-4a56-9b8c-7d6e5f4a3b2c.png",
    "provider_used": "fal_seedream",
    "mode": "text_to_image",
    "width": 1024,
    "height": 1024
  }
}

What the payload never contains

imagine.completed is intentionally a URL-and-metadata event about your own job. It never carries the prompt or negative prompt, the seed, moderation verdicts, ranking or quality scores, per-provider cost or token charges, pricing, or any account internals. Everything beyond the fields above stays in your account.

Need the prompt, seed, cost, or moderation detail for a job? Those live behind your authenticated account and are not exposed to webhook consumers — nor by the image generation API, which returns the same URL-and-metadata view.

Only successful jobs are delivered

This event fires exclusively from the success completion path. Jobs that are canceled or that fail do not emit imagine.completed, and there is no imagine.failed event in v1. Consequently status is always "SUCCEEDED" — never treat it as a discriminator.

To observe failures, use the synchronous image generation API response itself — POST /ai/imagine holds the connection and returns the failure or timeout directly (see Image generation). Emission is also best-effort: a webhook that cannot be recorded never blocks or fails the underlying image job, so a completed job is not a guarantee that a webhook fired. Treat the API response as the source of truth and the webhook as an at-least-once nudge.

Idempotent processing

Deliveries are retried on failure, so your endpoint may receive the same event more than once. Deduplicate on the envelope id (a stable ULID) — or, equivalently, on data.job_id, since a given job produces at most one event. Make your handler idempotent and return promptly; see Webhooks overview for retry and delivery semantics and Webhook deliveries for inspecting and replaying deliveries.

The catalog widens over time

New events are added by teeing more domain state-changes into the webhook platform. When that happens they appear here and become subscribable in the console — existing subscriptions are unaffected. Two rules keep growth non-breaking:

Watch the Versioning & changelog page for new events and api_version changes.

Next steps