Leonardo.AI · AsyncAPI Specification

Leonardo.AI Webhook Callbacks

Version 1.0.0

AsyncAPI description of Leonardo.AI's outbound webhook callback surface. Leonardo delivers asynchronous job-completion notifications to a customer- hosted HTTPS endpoint that is configured per Production API key. Instead of polling the Get a Single Generation endpoint, subscribers can receive a POST containing the generation result envelope. Scope of this document: Only the `image_generation.complete` event is documented verbatim by Leonardo in the public Guide to the Webhook Callback Feature, and only that event is modelled here. The Leonardo platform also runs video, upscale, and variation jobs through similarly asynchronous queues, but no separate event names or payload examples for those job classes are published in the public docs as of the source date below. Operators that have observed additional event names in production should extend the `oneOf` list in the publish operation and add the corresponding message + payload definitions. Source documentation (retrieved 2026-05-30): - Webhook callback guide: https://docs.leonardo.ai/docs/guide-to-the-webhook-callback-feature - Common reference (apis.yml link): https://docs.leonardo.ai/docs/webhook-callback-feature - API access dashboard (where the webhook URL and webhook API key are configured on a Production API key): https://app.leonardo.ai/api-access Delivery and security model: - Transport: HTTPS POST with `Content-Type: application/json`. - Authentication to the subscriber endpoint: optional bearer token. When a `webhookCallbackApiKey` is set on the Production API key, Leonardo adds the header `Authorization: Bearer ` to every callback request. - Source IP allowlist (documented in the webhook guide): 35.173.108.170 34.239.69.60 52.73.75.186 3.229.99.26 44.218.0.197 174.129.230.221 - Retry policy: not documented in the public webhook guide. - Signature header: none documented. Subscribers should rely on the bearer token and/or IP allowlist for authentication. - Registration: webhook URL and webhook API key are bound to a Production API key at creation time. To rotate them, create a new Production API key and delete the old one.

View Spec View on GitHub AIArtificial IntelligenceImage GenerationVideo GenerationGenerative AICreative3DDiffusionCanvaAsyncAPIWebhooksEvents

Channels

/leonardo/webhook
publish receiveLeonardoWebhook
Receive a Leonardo.AI webhook callback
Single subscriber endpoint that receives every Leonardo.AI webhook callback for the configured Production API key. The top-level `type` field on the JSON body identifies the event class; the inner `data.object` carries the resource that completed.

Messages

ImageGenerationComplete
Image generation complete
Fired when an image generation job submitted via POST /generations reaches the COMPLETE status.

Servers

https
subscriber {webhookCallbackUrl}
Customer-hosted HTTPS endpoint that receives webhook POSTs from Leonardo.AI. The URL is bound to a single Production API key via the `webhookCallbackUrl` field when the key is created in the API access dashboard.

AsyncAPI Specification

Raw ↑
asyncapi: 2.6.0
info:
  title: Leonardo.AI Webhook Callbacks
  version: '1.0.0'
  description: |-
    AsyncAPI description of Leonardo.AI's outbound webhook callback surface.
    Leonardo delivers asynchronous job-completion notifications to a customer-
    hosted HTTPS endpoint that is configured per Production API key. Instead of
    polling the Get a Single Generation endpoint, subscribers can receive a
    POST containing the generation result envelope.

    Scope of this document:
      Only the `image_generation.complete` event is documented verbatim by
      Leonardo in the public Guide to the Webhook Callback Feature, and only
      that event is modelled here. The Leonardo platform also runs video,
      upscale, and variation jobs through similarly asynchronous queues, but
      no separate event names or payload examples for those job classes are
      published in the public docs as of the source date below. Operators
      that have observed additional event names in production should extend
      the `oneOf` list in the publish operation and add the corresponding
      message + payload definitions.

    Source documentation (retrieved 2026-05-30):
      - Webhook callback guide:
          https://docs.leonardo.ai/docs/guide-to-the-webhook-callback-feature
      - Common reference (apis.yml link):
          https://docs.leonardo.ai/docs/webhook-callback-feature
      - API access dashboard (where the webhook URL and webhook API key are
        configured on a Production API key):
          https://app.leonardo.ai/api-access

    Delivery and security model:
      - Transport: HTTPS POST with `Content-Type: application/json`.
      - Authentication to the subscriber endpoint: optional bearer token.
        When a `webhookCallbackApiKey` is set on the Production API key,
        Leonardo adds the header `Authorization: Bearer <webhookCallbackApiKey>`
        to every callback request.
      - Source IP allowlist (documented in the webhook guide):
            35.173.108.170
            34.239.69.60
            52.73.75.186
            3.229.99.26
            44.218.0.197
            174.129.230.221
      - Retry policy: not documented in the public webhook guide.
      - Signature header: none documented. Subscribers should rely on the
        bearer token and/or IP allowlist for authentication.
      - Registration: webhook URL and webhook API key are bound to a
        Production API key at creation time. To rotate them, create a new
        Production API key and delete the old one.

  contact:
    name: Leonardo.AI API Support
    url: https://docs.leonardo.ai/
  license:
    name: Leonardo.AI Terms of Service
    url: https://leonardo.ai/terms-of-service/

defaultContentType: application/json

servers:
  subscriber:
    url: '{webhookCallbackUrl}'
    protocol: https
    description: |-
      Customer-hosted HTTPS endpoint that receives webhook POSTs from
      Leonardo.AI. The URL is bound to a single Production API key via the
      `webhookCallbackUrl` field when the key is created in the API access
      dashboard.
    variables:
      webhookCallbackUrl:
        default: https://example.com/leonardo/webhook
        description: |-
          Fully-qualified HTTPS URL of the subscriber endpoint. Must use the
          HTTPS protocol; HTTP is rejected at key-creation time.
    security:
      - bearerToken: []
      - ipAllowList: []

channels:
  /leonardo/webhook:
    description: |-
      Single subscriber endpoint that receives every Leonardo.AI webhook
      callback for the configured Production API key. The top-level `type`
      field on the JSON body identifies the event class; the inner
      `data.object` carries the resource that completed.
    bindings:
      http:
        type: request
        method: POST
        bindingVersion: '0.3.0'
    publish:
      operationId: receiveLeonardoWebhook
      summary: Receive a Leonardo.AI webhook callback
      description: |-
        Leonardo POSTs a JSON event envelope to the subscriber endpoint when
        an asynchronous job that was submitted under the bound Production
        API key reaches a terminal state. Subscribers should respond with a
        2xx status code; the public webhook guide does not document a retry
        schedule.
      bindings:
        http:
          bindingVersion: '0.3.0'
          headers:
            type: object
            properties:
              Authorization:
                type: string
                description: |-
                  When the Production API key has a `webhookCallbackApiKey`
                  configured, Leonardo sends it as a bearer token in this
                  header: `Authorization: Bearer <webhookCallbackApiKey>`.
                  Absent when no webhook API key is configured.
                example: Bearer abcd
              Content-Type:
                type: string
                enum:
                  - application/json
              User-Agent:
                type: string
                description: |-
                  Sample value observed in the public webhook guide.
                example: axios/1.4.0
      message:
        oneOf:
          - $ref: '#/components/messages/ImageGenerationComplete'

components:
  securitySchemes:
    bearerToken:
      type: httpApiKey
      in: header
      name: Authorization
      description: |-
        Optional bearer token. When the Production API key is created with a
        `webhookCallbackApiKey`, Leonardo includes
        `Authorization: Bearer <webhookCallbackApiKey>` on every callback.
        Subscribers should reject requests that do not present the expected
        bearer value.
    ipAllowList:
      type: httpApiKey
      in: header
      name: X-Forwarded-For
      description: |-
        Source-IP allowlisting against the six documented Leonardo egress
        addresses: 35.173.108.170, 34.239.69.60, 52.73.75.186, 3.229.99.26,
        44.218.0.197, 174.129.230.221. Modelled here as an httpApiKey scheme
        because AsyncAPI 2.6 has no first-class allowlist security type.

  messages:
    ImageGenerationComplete:
      name: ImageGenerationComplete
      title: Image generation complete
      summary: |-
        Fired when an image generation job submitted via POST /generations
        reaches the COMPLETE status.
      contentType: application/json
      payload:
        $ref: '#/components/schemas/ImageGenerationCompleteEnvelope'
      examples:
        - name: imageGenerationCompleteSample
          summary: >-
            Verbatim sample payload from the public Leonardo webhook callback
            guide.
          payload:
            type: image_generation.complete
            object: generation
            timestamp: 1699490546932
            api_version: v1
            data:
              object:
                id: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                createdAt: '2023-11-09T00:42:22.707Z'
                updatedAt: '2023-11-09T00:42:26.740Z'
                userId: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                public: false
                flagged: false
                nsfw: false
                status: COMPLETE
                coreModel: SD
                guidanceScale: 7
                imageHeight: 512
                imageWidth: 512
                inferenceSteps: 30
                initGeneratedImageId: null
                initImageId: null
                initStrength: null
                initType: null
                initUpscaledImageId: null
                modelId: 6bef9f1b-29cb-40c7-b9df-32b51c1f67d3
                negativePrompt: ''
                prompt: An oil painting of a cat
                quantity: 1
                sdVersion: v2
                tiling: false
                imageAspectRatio: null
                tokenCost: 0
                negativeStylePrompt: ''
                seed: '905778432'
                scheduler: EULER_DISCRETE
                presetStyle: null
                promptMagic: false
                canvasInitImageId: null
                canvasMaskImageId: null
                canvasRequest: false
                api: true
                poseImage2Image: false
                imagePromptStrength: null
                category: null
                poseImage2ImageType: null
                highContrast: false
                apiDollarCost: '9'
                poseImage2ImageWeight: null
                alchemy: null
                contrastRatio: null
                highResolution: null
                expandedDomain: null
                promptMagicVersion: null
                unzoom: null
                unzoomAmount: null
                apiKeyId: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                photoReal: false
                promptMagicStrength: null
                photoRealStrength: null
                imageToImage: false
                controlnetsUsed: false
                model:
                  id: 6bef9f1b-29cb-40c7-b9df-32b51c1f67d3
                  createdAt: '2023-01-06T01:02:38.315Z'
                  updatedAt: '2023-03-01T11:45:06.428Z'
                  name: Leonardo Creative
                  description: >-
                    An alternative finetune of SD 2.1 that brings a little
                    more creative interpretation to the mix.
                  public: true
                  userId: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                  flagged: false
                  nsfw: false
                  official: true
                  status: COMPLETE
                  classPrompt: null
                  coreModel: SD
                  initDatasetId: null
                  instancePrompt: null
                  sdVersion: v2
                  trainingEpoch: null
                  trainingSteps: null
                  tokenCost: null
                  batchSize: 4
                  learningRate: null
                  type: GENERAL
                  modelHeight: 768
                  modelWidth: 768
                  leonardoInstancePrompt: null
                  trainingStrength: MEDIUM
                  featured: false
                  featuredImageId: null
                  featuredPosition: 4
                  api: false
                  favouriteCount: 0
                  imageCount: 2416039
                  enhancedModeration: false
                  apiDollarCost: null
                  apiKeyId: null
                  modelLRN: null
                images:
                  - id: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                    createdAt: '2023-11-09T00:42:26.733Z'
                    updatedAt: '2023-11-09T00:42:26.733Z'
                    userId: ef8b8386-94f7-48d1-b10e-e87fd4dee6e6
                    url: >-
                      https://cdn.leonardo.ai/users/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/generations/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX/Leonardo_Creative_An_oil_painting_of_a_cat_0.jpg
                    generationId: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                    nobgId: null
                    nsfw: false
                    likeCount: 0
                    trendingScore: 0
                    public: false
                apiKey:
                  id: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                  createdAt: '2023-11-07T00:11:07.274Z'
                  userId: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                  key: XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
                  lastUsed: '2023-11-07T00:11:07.274Z'
                  name: webhook with key
                  type: PRODUCTION
                  webhookCallbackUrl: >-
                    https://webhook.site/cc21af5f-4caa-498e-8f26-20c664680b73
                  webhookCallbackApiKey: abcd

  schemas:
    ImageGenerationCompleteEnvelope:
      type: object
      description: |-
        Top-level event envelope delivered for `image_generation.complete`.
        Field set is taken verbatim from the public Leonardo webhook callback
        guide.
      required:
        - type
        - object
        - timestamp
        - api_version
        - data
      properties:
        type:
          type: string
          description: Event class. Documented value is `image_generation.complete`.
          enum:
            - image_generation.complete
        object:
          type: string
          description: Resource class carried in `data.object`.
          enum:
            - generation
        timestamp:
          type: integer
          format: int64
          description: Unix epoch time in milliseconds.
          example: 1699490546932
        api_version:
          type: string
          description: Webhook envelope version.
          enum:
            - v1
        data:
          type: object
          required:
            - object
          properties:
            object:
              $ref: '#/components/schemas/Generation'

    Generation:
      type: object
      description: |-
        Generation resource as delivered inside `data.object` for an
        `image_generation.complete` event. Field names and example values
        mirror the public guide exactly; types are inferred from the sample
        payload.
      properties:
        id:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        userId:
          type: string
          format: uuid
        public:
          type: boolean
        flagged:
          type: boolean
        nsfw:
          type: boolean
        status:
          type: string
          description: Terminal status for the generation.
          example: COMPLETE
        coreModel:
          type: string
          example: SD
        guidanceScale:
          type: number
        imageHeight:
          type: integer
        imageWidth:
          type: integer
        inferenceSteps:
          type: integer
        initGeneratedImageId:
          type: string
          nullable: true
        initImageId:
          type: string
          nullable: true
        initStrength:
          type: number
          nullable: true
        initType:
          type: string
          nullable: true
        initUpscaledImageId:
          type: string
          nullable: true
        modelId:
          type: string
          format: uuid
          nullable: true
        negativePrompt:
          type: string
        prompt:
          type: string
        quantity:
          type: integer
        sdVersion:
          type: string
        tiling:
          type: boolean
        imageAspectRatio:
          type: string
          nullable: true
        tokenCost:
          type: number
        negativeStylePrompt:
          type: string
        seed:
          type: string
        scheduler:
          type: string
        presetStyle:
          type: string
          nullable: true
        promptMagic:
          type: boolean
          nullable: true
        canvasInitImageId:
          type: string
          nullable: true
        canvasMaskImageId:
          type: string
          nullable: true
        canvasRequest:
          type: boolean
        api:
          type: boolean
        poseImage2Image:
          type: boolean
        imagePromptStrength:
          type: number
          nullable: true
        category:
          type: string
          nullable: true
        poseImage2ImageType:
          type: string
          nullable: true
        highContrast:
          type: boolean
          nullable: true
        apiDollarCost:
          type: string
          description: |-
            USD cost of the generation expressed as a string to preserve
            decimal precision, mirroring the sample payload.
        poseImage2ImageWeight:
          type: number
          nullable: true
        alchemy:
          type: boolean
          nullable: true
        contrastRatio:
          type: number
          nullable: true
        highResolution:
          type: boolean
          nullable: true
        expandedDomain:
          type: boolean
          nullable: true
        promptMagicVersion:
          type: string
          nullable: true
        unzoom:
          type: boolean
          nullable: true
        unzoomAmount:
          type: number
          nullable: true
        apiKeyId:
          type: string
          format: uuid
        photoReal:
          type: boolean
        promptMagicStrength:
          type: number
          nullable: true
        photoRealStrength:
          type: number
          nullable: true
        imageToImage:
          type: boolean
        controlnetsUsed:
          type: boolean
        model:
          $ref: '#/components/schemas/Model'
        images:
          type: array
          items:
            $ref: '#/components/schemas/GeneratedImage'
        apiKey:
          $ref: '#/components/schemas/ApiKey'

    Model:
      type: object
      description: |-
        Snapshot of the model that produced the generation, nested inside the
        generation envelope.
      properties:
        id:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        name:
          type: string
        description:
          type: string
        public:
          type: boolean
        userId:
          type: string
          format: uuid
        flagged:
          type: boolean
        nsfw:
          type: boolean
        official:
          type: boolean
        status:
          type: string
        classPrompt:
          type: string
          nullable: true
        coreModel:
          type: string
        initDatasetId:
          type: string
          nullable: true
        instancePrompt:
          type: string
          nullable: true
        sdVersion:
          type: string
        trainingEpoch:
          type: integer
          nullable: true
        trainingSteps:
          type: integer
          nullable: true
        tokenCost:
          type: number
          nullable: true
        batchSize:
          type: integer
        learningRate:
          type: number
          nullable: true
        type:
          type: string
          example: GENERAL
        modelHeight:
          type: integer
        modelWidth:
          type: integer
        leonardoInstancePrompt:
          type: string
          nullable: true
        trainingStrength:
          type: string
        featured:
          type: boolean
        featuredImageId:
          type: string
          nullable: true
        featuredPosition:
          type: integer
        api:
          type: boolean
        favouriteCount:
          type: integer
        imageCount:
          type: integer
        enhancedModeration:
          type: boolean
        apiDollarCost:
          type: string
          nullable: true
        apiKeyId:
          type: string
          nullable: true
        modelLRN:
          type: string
          nullable: true

    GeneratedImage:
      type: object
      description: |-
        Image asset produced by the generation. The `url` points to the CDN
        location where the rendered image can be fetched.
      properties:
        id:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
        userId:
          type: string
          format: uuid
        url:
          type: string
          format: uri
        generationId:
          type: string
          format: uuid
        nobgId:
          type: string
          nullable: true
        nsfw:
          type: boolean
        likeCount:
          type: integer
        trendingScore:
          type: number
        public:
          type: boolean

    ApiKey:
      type: object
      description: |-
        Snapshot of the Production API key the generation was billed to,
        including the webhook callback URL and webhook API key that triggered
        this delivery.
      properties:
        id:
          type: string
          format: uuid
        createdAt:
          type: string
          format: date-time
        userId:
          type: string
          format: uuid
        key:
          type: string
        lastUsed:
          type: string
          format: date-time
        name:
          type: string
        type:
          type: string
          enum:
            - PRODUCTION
        webhookCallbackUrl:
          type: string
          format: uri
        webhookCallbackApiKey:
          type: string