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:
- Subscription must be user-scoped. You subscribe your endpoint without naming a guild; a guild-scoped subscription is rejected for this event.
- Delivery is own-data-only. At fan-out, the platform matches the event owner against the endpoint app owner (across your linked identities). You only ever receive events for image jobs owned by your own account — never another user's.
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:
{
"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:
- Only cataloged events are ever published. The platform will not deliver an event
typethat is not in the catalog, so you never receive an undocumented event. - The envelope shape is versioned. A change to an event's
datacontract is reflected by a newapi_version, letting you branch on it explicitly.
Watch the Versioning & changelog page for new events and
api_version changes.
Next steps
- Webhooks overview — endpoints, subscriptions, and delivery semantics.
- Signature verification — verify a delivery is genuinely from Krallo.
- Webhook deliveries — list, inspect, and replay past deliveries.
- Image generation — create the jobs that produce these events.