openapi: 3.0.3
info:
  title: DPDP reference webhook listener
  version: 1.0.0
  description: |
    Callback contract implemented by the reference webhook listeners (`webhook-listener.mjs`
    and `webhook-listener.py`). This is a lightweight receiver for subscription verification
    and inspecting delivered events during development and tryouts.
servers:
  - url: https://receiver.example.com
paths:
  /dpdp/events:
    post:
      summary: Verify a subscription callback URL or accept an event delivery
      description: |
        Identity Server invokes this endpoint during subscription verification and event delivery.

        For verification (`type: "subscription.verification"`), the message carries a subscription ID,
        topics array, and challenge. The receiver echoes the challenge back as plain text with HTTP 200.

        For event deliveries, the message carries the event payload (or compact signedPayload).
        If SHARED_SECRET is configured, the receiver validates the `event-signature` HMAC-SHA256 header.
        The listener logs all incoming headers and payloads to the console and returns HTTP 202 Accepted.
      parameters:
        - $ref: '#/components/parameters/DeliveryId'
        - $ref: '#/components/parameters/EventSignature'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/SubscriptionVerification'
                - $ref: '#/components/schemas/SignedDelivery'
      responses:
        '200':
          description: Verification succeeded; response body is the exact challenge string.
          content:
            text/plain:
              schema:
                type: string
        '202':
          description: Event delivery accepted and logged to stdout.
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: accepted
        '400':
          description: Malformed JSON or invalid verification challenge.
        '401':
          description: HMAC-SHA256 signature verification failed.
        '404':
          description: Unknown route path.
        '405':
          description: Unsupported HTTP method (POST required).
        '413':
          description: Request body exceeds 1 MiB limit.
        '415':
          description: Content-Type is not application/json.
components:
  parameters:
    DeliveryId:
      name: Delivery-Id
      in: header
      required: false
      description: Stable delivery identifier.
      schema:
        type: string
    EventSignature:
      name: event-signature
      in: header
      required: false
      description: HMAC-SHA256 of the raw request-body bytes using the configured shared secret.
      schema:
        type: string
        pattern: '^sha256=[0-9a-f]{64}$'
        example: sha256=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
  schemas:
    SubscriptionVerification:
      type: object
      required: [type, subscriptionId, topics, challenge]
      properties:
        type:
          type: string
          enum: [subscription.verification]
        subscriptionId:
          type: string
        topics:
          type: array
          minItems: 1
          items:
            type: string
        challenge:
          type: string
    SignedDelivery:
      type: object
      additionalProperties: true
      properties:
        signedPayload:
          type: string
          description: Compact tenant-signed JWS containing event claims.
