asyncapi: 3.0.0
info:
  title: Stepes Public API Webhooks
  version: 2.0.0
  description: >-
    Signed notifications for quote, project, and delivery changes. Events may
    be retried, so webhook handlers must deduplicate them by event id.
servers:
  customerEndpoint:
    host: customer.example
    protocol: https
    description: The HTTPS endpoint registered through POST /v2/webhooks.
channels:
  clientWebhook:
    address: /registered-webhook-path
    description: Customer-owned callback URL. Redirects and private network targets are rejected.
    messages:
      quoteCreated: {$ref: '#/components/messages/QuoteCreated'}
      quoteUpdated: {$ref: '#/components/messages/QuoteUpdated'}
      quoteSubmitted: {$ref: '#/components/messages/QuoteSubmitted'}
      quoteAccepted: {$ref: '#/components/messages/QuoteAccepted'}
      projectCreated: {$ref: '#/components/messages/ProjectCreated'}
      projectUpdated: {$ref: '#/components/messages/ProjectUpdated'}
      projectCancelled: {$ref: '#/components/messages/ProjectCancelled'}
      projectCompleted: {$ref: '#/components/messages/ProjectCompleted'}
      deliveryReady: {$ref: '#/components/messages/DeliveryReady'}
operations:
  deliverLifecycleEvent:
    action: send
    summary: Deliver a persisted Stepes lifecycle event
    channel:
      $ref: '#/channels/clientWebhook'
    messages:
      - $ref: '#/channels/clientWebhook/messages/quoteCreated'
      - $ref: '#/channels/clientWebhook/messages/quoteUpdated'
      - $ref: '#/channels/clientWebhook/messages/quoteSubmitted'
      - $ref: '#/channels/clientWebhook/messages/quoteAccepted'
      - $ref: '#/channels/clientWebhook/messages/projectCreated'
      - $ref: '#/channels/clientWebhook/messages/projectUpdated'
      - $ref: '#/channels/clientWebhook/messages/projectCancelled'
      - $ref: '#/channels/clientWebhook/messages/projectCompleted'
      - $ref: '#/channels/clientWebhook/messages/deliveryReady'
components:
  messages:
    QuoteCreated:
      name: quote.created
      title: Quote created
      summary: A quote was created.
      x-stepes-category: Quotes
      x-stepes-trigger: A new quote became available after quote or project creation.
      x-stepes-source-operations: [createQuote, createProject]
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: quote.created}}
    QuoteUpdated:
      name: quote.updated
      title: Quote updated
      summary: Quote inputs, pricing, or lifecycle state changed.
      x-stepes-category: Quotes
      x-stepes-trigger: Quote details, pricing, or status changed.
      x-stepes-source-operations: [updateQuote]
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: quote.updated}}
    QuoteSubmitted:
      name: quote.submitted
      title: Quote submitted
      summary: A quote was submitted and can no longer be edited.
      x-stepes-category: Quotes
      x-stepes-trigger: POST /v2/quotes/{quoteId}/submit completed.
      x-stepes-source-operations: [submitQuote]
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: quote.submitted}}
    QuoteAccepted:
      name: quote.accepted
      title: Quote accepted
      summary: A quote was accepted and project creation started.
      x-stepes-category: Quotes
      x-stepes-trigger: Quote acceptance completed and a translation project was created.
      x-stepes-source-operations: [acceptQuote, createProject]
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: quote.accepted}}
    ProjectCreated:
      name: project.created
      title: Project created
      summary: A translation project was created.
      x-stepes-category: Projects
      x-stepes-trigger: POST /v2/projects or quote acceptance created a project.
      x-stepes-source-operations: [createProject, acceptQuote]
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: project.created}}
    ProjectUpdated:
      name: project.updated
      title: Project updated
      summary: Project status, progress, or delivery availability changed.
      x-stepes-category: Projects
      x-stepes-trigger: The project's status, progress, or available results changed.
      x-stepes-source-operations: []
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: project.updated}}
    ProjectCancelled:
      name: project.cancelled
      title: Project cancelled
      summary: A project was cancelled.
      x-stepes-category: Projects
      x-stepes-trigger: A project reached the cancelled state.
      x-stepes-source-operations: [cancelProject]
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: project.cancelled}}
    ProjectCompleted:
      name: project.completed
      title: Project completed
      summary: All requested translations are complete.
      x-stepes-category: Projects
      x-stepes-trigger: The project reached the completed state.
      x-stepes-source-operations: []
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: project.completed}}
    DeliveryReady:
      name: delivery.ready
      title: Delivery ready
      summary: A translated file or structured result is ready.
      x-stepes-category: Deliveries
      x-stepes-trigger: A new project delivery became available for download or retrieval.
      x-stepes-source-operations: []
      x-stepes-schema-version: '1.0'
      contentType: application/json
      headers: {$ref: '#/components/schemas/WebhookHeaders'}
      payload:
        allOf:
          - $ref: '#/components/schemas/EventEnvelope'
          - type: object
            properties: {type: {const: delivery.ready}}
  schemas:
    WebhookHeaders:
      type: object
      additionalProperties: false
      required:
        - Stepes-Webhook-Id
        - Stepes-Webhook-Delivery-Id
        - Stepes-Webhook-Timestamp
        - Stepes-Webhook-Signature
      properties:
        Stepes-Webhook-Id:
          type: string
          pattern: '^evt_'
          description: Stable event identifier used for consumer deduplication.
        Stepes-Webhook-Delivery-Id:
          type: string
          pattern: '^whd_'
          description: Stable delivery identifier for this endpoint and event.
        Stepes-Webhook-Timestamp:
          type: string
          pattern: '^[0-9]+$'
          description: Unix timestamp included in the signed material.
        Stepes-Webhook-Signature:
          type: string
          pattern: '^v1=[a-f0-9]{64}(,v1=[a-f0-9]{64})?$'
    EventType:
      type: string
      enum:
        - quote.created
        - quote.updated
        - quote.submitted
        - quote.accepted
        - project.created
        - project.updated
        - project.cancelled
        - project.completed
        - delivery.ready
    EventEnvelope:
      type: object
      additionalProperties: false
      required: [id, object, type, created_at, data]
      properties:
        id:
          type: string
          pattern: '^evt_'
          description: Stable event ID used for consumer deduplication.
        object: {const: event}
        type: {$ref: '#/components/schemas/EventType'}
        created_at: {type: string, format: date-time}
        data:
          type: object
          additionalProperties: false
          required: [object]
          properties:
            object:
              type: object
              additionalProperties: true
              description: Quote, project, or delivery data using public API fields and IDs.
