openapi: 3.1.0
info:
  title: PSP Merchant Outbound Webhook API
  version: 1.1.0
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary
  description: |
    Canonical outbound contract for PSP merchant events delivered to
    merchant-owned HTTPS endpoints. The request body is one of five envelopes;
    route on the `X-Webhook-Event` header first.

    - `ClassifiedMerchantWebhookEnvelope`: payment intent, transfer and credit
      card lifecycle events. `data` always carries classification schema
      version 1 and the resolved public payment classification.
    - `UnclassifiedMerchantWebhookEnvelope`: refund and account freeze
      lifecycle events. `data` cannot carry classification fields.
    - `MerchantSettlementWebhookEnvelope`: `merchant_settlement.*.v1` events
      for settlement items. Different top-level fields; amounts are decimal
      strings.
    - `WithdrawalStatusWebhookEnvelope` and `SettlementStatusWebhookEnvelope`:
      flat status bodies sent by the withdrawal and settlement workflows.

    Amounts are integers in the currency's minor unit unless a schema states
    otherwise. Fields documented as aliases always carry the same value.
    Only the `data` objects of `ClassifiedMerchantWebhookEnvelope` and
    `UnclassifiedMerchantWebhookEnvelope` stay open
    (`additionalProperties: true`) so PSP can add fields without a new
    contract version. `MerchantSettlementWebhookEnvelope`, its
    `MerchantSettlementEventData`, both flat status envelopes, the classified
    and unclassified envelopes themselves, `InvoicePaymentPolicy` and
    `ResolvedPaymentClassification` reject undeclared fields. Retries and
    operator redeliveries resend the stored body unchanged, so fields
    introduced later may be absent from older events. A callback regenerated
    by an operator refresh is stored and resent the same way; bodies stored
    before a refresh rebuilt the complete event can carry only a subset of the
    fields documented as required for first deliveries (for example
    `classification` on payment events), and may omit fields that are optional
    for first deliveries as well (for example the refund `fee_amount` or
    `original_intent_type`). Stable taxonomy IDs,
    direction, provenance, aliases,
    defaults, and legacy flat classification fields are intentionally not
    exposed.
servers:
  - url: https://{merchantWebhookHost}
    description: Merchant-owned delivery endpoint configured for the account.
    variables:
      merchantWebhookHost:
        default: merchant.example.com
security:
  - webhookSignature: []
webhooks:
  merchantEvent:
    post:
      operationId: deliverMerchantEvent
      summary: Deliver a merchant transaction event
      description: |
        PSP signs the exact request body as `<X-Timestamp>.<raw-body>` with the
        account-level Ed25519 signing key identified by `X-Webhook-Key-ID`.
        Verify the signature and timestamp window before parsing the body, and
        deduplicate by `X-Webhook-Event-ID`.
      parameters:
        - $ref: '#/components/parameters/Timestamp'
        - $ref: '#/components/parameters/Signature'
        - $ref: '#/components/parameters/SignatureAlgorithm'
        - $ref: '#/components/parameters/WebhookKeyID'
        - $ref: '#/components/parameters/WebhookVersion'
        - $ref: '#/components/parameters/WebhookID'
        - $ref: '#/components/parameters/EventType'
        - $ref: '#/components/parameters/EventID'
        - $ref: '#/components/parameters/MerchantAccountID'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/MerchantWebhookEnvelope'
      responses:
        '200':
          description: Event accepted.
        '204':
          description: Event accepted without a response body.
components:
  securitySchemes:
    webhookSignature:
      type: apiKey
      in: header
      name: X-Signature
      description: Ed25519 signature over `<X-Timestamp>.<raw-body>`.
  parameters:
    Timestamp:
      name: X-Timestamp
      in: header
      required: true
      description: |
        Unix time in seconds (UTC) at which PSP signed this HTTP attempt. It is
        regenerated on every attempt (automatic retry, merchant manual retry and
        operator redelivery), so it is neither the event time nor a
        deduplication key. Reject requests whose value differs from the
        receiver's clock by more than 300 seconds.
      schema: { type: string, pattern: '^[0-9]+$' }
    Signature:
      name: X-Signature
      in: header
      required: true
      description: |
        Standard Base64 encoding of the 64-byte Ed25519 signature over the
        ASCII bytes `<X-Timestamp>.<raw request body>`. It is recomputed on
        every attempt because `X-Timestamp` changes. Verify against the raw body
        bytes, never a re-serialized JSON document.
      schema: { type: string, minLength: 1 }
    SignatureAlgorithm:
      name: X-Signature-Algorithm
      in: header
      required: true
      description: Signature algorithm; always `ed25519`.
      schema: { type: string, const: ed25519 }
    WebhookKeyID:
      name: X-Webhook-Key-ID
      in: header
      required: true
      description: |
        Identifier of the account-level signing key bound to this delivery.
        All attempts of a delivery, including operator redeliveries of it, are
        signed with the originally bound key. Select the public key by this ID
        and keep retired keys available during rotation.
      schema: { type: string, minLength: 1 }
    WebhookVersion:
      name: X-Webhook-Version
      in: header
      required: true
      description: |
        Version of the delivery header and signing contract, fixed to
        `2026-06-11`. It does not version the body; merchant settlement bodies
        carry their own `schema_version`.
      schema: { type: string, const: '2026-06-11' }
    WebhookID:
      name: X-Webhook-ID
      in: header
      required: true
      description: |
        Delivery ID. It stays the same across automatic retries and merchant
        manual retries of one delivery. An operator redelivery creates a new
        delivery with a new `X-Webhook-ID` while keeping the same
        `X-Webhook-Event-ID` and body. Use it to correlate attempts with PSP
        delivery records, not for business deduplication.
      schema: { type: string, format: uuid }
    EventType:
      name: X-Webhook-Event
      in: header
      required: true
      description: |
        Event type of the body: the body `event` for event/data envelopes, or
        the body `event_type` for merchant settlement, withdrawal and settlement
        status bodies. Route on this header before parsing the body; record and
        acknowledge event types you do not handle.
      schema: { type: string, minLength: 1 }
    EventID:
      name: X-Webhook-Event-ID
      in: header
      required: true
      description: |
        Event ID. It never changes across attempts, manual retries or operator
        redeliveries of the same event and is the recommended deduplication key.
        For merchant settlement events it equals the body `event_id`; for other
        events it is a stable PSP-derived ID that is not repeated in the body.
      schema: { type: string, format: uuid }
    MerchantAccountID:
      name: X-Merchant-Account-ID
      in: header
      required: true
      description: |
        Merchant account the delivery belongs to; identical on every attempt.
        Use it to scope events whose `data` has no account ID, such as refund
        completion events.
      schema: { type: string, format: uuid }
  schemas:
    MerchantWebhookEnvelope:
      oneOf:
        - $ref: '#/components/schemas/ClassifiedMerchantWebhookEnvelope'
        - $ref: '#/components/schemas/UnclassifiedMerchantWebhookEnvelope'
        - $ref: '#/components/schemas/MerchantSettlementWebhookEnvelope'
        - $ref: '#/components/schemas/WithdrawalStatusWebhookEnvelope'
        - $ref: '#/components/schemas/SettlementStatusWebhookEnvelope'
    ClassifiedMerchantWebhookEnvelope:
      type: object
      additionalProperties: false
      description: Payment intent, transfer and credit card events with resolved payment classification.
      required: [event, timestamp, data]
      allOf:
        - if:
            properties:
              event: { const: payment.intent.completed }
          then:
            properties:
              data:
                $ref: '#/components/schemas/PaymentIntentCompletedData'
        - if:
            properties:
              event: { const: payment.intent.partially_paid }
          then:
            properties:
              data:
                $ref: '#/components/schemas/PaymentIntentPartiallyPaidData'
        - if:
            properties:
              event: { const: payment.intent.expired }
          then:
            properties:
              data:
                $ref: '#/components/schemas/PaymentIntentExpiredData'
        - if:
            properties:
              event: { const: payment.intent.canceled }
          then:
            properties:
              data:
                $ref: '#/components/schemas/PaymentIntentCanceledData'
        - if:
            properties:
              event: { const: payment.transfer.completed }
          then:
            properties:
              data:
                $ref: '#/components/schemas/TransferCompletedData'
        - if:
            properties:
              event: { const: payment.transfer.failed }
          then:
            properties:
              data:
                $ref: '#/components/schemas/TransferFailedData'
        - if:
            properties:
              event: { const: payment.transfer.returned }
          then:
            properties:
              data:
                $ref: '#/components/schemas/TransferReturnedData'
        - if:
            properties:
              event: { const: creditcard_invoice.captured }
          then:
            properties:
              data:
                $ref: '#/components/schemas/CreditCardInvoiceCapturedData'
        - if:
            properties:
              event: { const: creditcard_invoice.3ds_timeout }
          then:
            properties:
              data:
                $ref: '#/components/schemas/CreditCardInvoice3DSTimeoutData'
      properties:
        event:
          $ref: '#/components/schemas/ClassifiedMerchantEventType'
        timestamp:
          type: string
          format: date-time
          description: Time the event occurred (RFC 3339, may include fractional seconds and an offset).
        data:
          $ref: '#/components/schemas/ClassifiedMerchantEventData'
    UnclassifiedMerchantWebhookEnvelope:
      type: object
      additionalProperties: false
      description: Refund and account lifecycle events without payment classification.
      required: [event, timestamp, data]
      allOf:
        - if:
            properties:
              event: { const: payment.refund.completed }
          then:
            properties:
              data:
                $ref: '#/components/schemas/PaymentRefundCompletedData'
        - if:
            properties:
              event: { const: payment.transfer_refund.completed }
          then:
            properties:
              data:
                $ref: '#/components/schemas/TransferRefundCompletedData'
        - if:
            properties:
              event: { const: payment.refund.failed }
          then:
            properties:
              data:
                $ref: '#/components/schemas/PaymentRefundFailedData'
        - if:
            properties:
              event: { const: account.frozen }
          then:
            properties:
              data:
                $ref: '#/components/schemas/AccountFrozenData'
        - if:
            properties:
              event: { const: account.unfrozen }
          then:
            properties:
              data:
                $ref: '#/components/schemas/AccountUnfrozenData'
      properties:
        event:
          $ref: '#/components/schemas/UnclassifiedMerchantEventType'
        timestamp:
          type: string
          format: date-time
          description: Time the event occurred (RFC 3339, may include fractional seconds and an offset).
        data:
          $ref: '#/components/schemas/UnclassifiedMerchantEventData'
    ClassifiedMerchantEventType:
      type: string
      enum:
        - payment.intent.completed
        - payment.intent.partially_paid
        - payment.intent.expired
        - payment.intent.canceled
        - payment.transfer.completed
        - payment.transfer.failed
        - payment.transfer.returned
        - creditcard_invoice.captured
        - creditcard_invoice.3ds_timeout
    UnclassifiedMerchantEventType:
      type: string
      enum:
        - payment.refund.completed
        - payment.transfer_refund.completed
        - payment.refund.failed
        - account.frozen
        - account.unfrozen
    ClassifiedMerchantEventData:
      type: object
      additionalProperties: true
      not:
        required: [payment_method]
      required: [classification_schema_version, classification]
      properties:
        classification_schema_version:
          type: integer
          const: 1
        classification:
          $ref: '#/components/schemas/ResolvedPaymentClassification'
    PaymentIntentCompletedData:
      type: object
      additionalProperties: true
      description: Invoice paid in full, including the final payment of a multi-payment invoice.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required:
        - intent_id
        - intent_number
        - merchant_id
        - merchant_account_id
        - account_id
        - amount
        - paid_amount
        - fee_amount
        - net_amount
        - current_payment_amount
        - remaining_amount
        - is_partial_payment
        - is_final_payment
        - payment_policy
        - currency
        - description
        - merchant_order_id
        - provider_transaction_id
        - provider_tx_id
        - payer_info
        - payer_name
        - payer_tax_id
        - completed_at
      properties:
        intent_id:
          type: string
          format: uuid
          description: PSP payment intent ID.
        intent_number:
          type: string
          description: PSP payment intent number.
        invoice_number:
          type: string
          description: Alias of intent_number with the same value; absent from events produced before 2026-09-09.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        merchant_account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        account_id:
          type: string
          format: uuid
          description: Alias of merchant_account_id with the same value.
        amount:
          type: integer
          format: int64
          description: Invoice amount in minor units.
        paid_amount:
          type: integer
          format: int64
          description: Cumulative paid amount in minor units.
        fee_amount:
          type: integer
          format: int64
          description: Merchant fee in minor units.
        net_amount:
          type: integer
          format: int64
          description: Net amount credited to the merchant in minor units.
        current_payment_amount:
          type: integer
          format: int64
          description: Amount of the payment that triggered this event, in minor units.
        remaining_amount:
          type: integer
          format: int64
          description: Amount still payable in minor units.
        is_partial_payment:
          type: boolean
          const: false
          description: Always false for this event.
        is_final_payment:
          type: boolean
          const: true
          description: Always true for this event.
        payment_policy:
          $ref: '#/components/schemas/InvoicePaymentPolicy'
          description: Payment acceptance policy of the invoice.
        currency:
          type: string
          description: ISO 4217 currency code.
        description:
          type: string
          description: Invoice description; empty when none was supplied.
        merchant_order_id:
          type: string
          description: Merchant order reference; empty when none was supplied.
        provider_transaction_id:
          type: string
          description: Provider transaction reference; empty when unavailable.
        provider_tx_id:
          type: string
          description: Alias of provider_transaction_id with the same value.
        payer_info:
          type: [object, 'null']
          additionalProperties: true
          description: Payer details reported by the provider (for example cpf_cnpj, name, email); null when unavailable.
        payer_name:
          type: string
          description: Payer name; empty when unavailable.
        payer_tax_id:
          type: string
          description: Payer tax ID; empty when unavailable.
        completed_at:
          type: string
          format: date-time
          description: Completion time; equals the envelope timestamp.
    PaymentIntentPartiallyPaidData:
      type: object
      additionalProperties: true
      description: A payment was received but the invoice is not fully paid.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required:
        - intent_id
        - intent_number
        - merchant_id
        - account_id
        - amount
        - paid_amount
        - current_payment_amount
        - remaining_amount
        - is_partial_payment
        - is_final_payment
        - payment_policy
        - currency
        - provider_tx_id
        - payer_name
        - payer_tax_id
        - partially_paid_at
      properties:
        intent_id:
          type: string
          format: uuid
          description: PSP payment intent ID.
        intent_number:
          type: string
          description: PSP payment intent number.
        invoice_number:
          type: string
          description: Alias of intent_number with the same value; absent from events produced before 2026-09-09.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        amount:
          type: integer
          format: int64
          description: Invoice amount in minor units.
        paid_amount:
          type: integer
          format: int64
          description: Cumulative paid amount in minor units.
        current_payment_amount:
          type: integer
          format: int64
          description: Amount of the payment that triggered this event, in minor units.
        remaining_amount:
          type: integer
          format: int64
          description: Amount still payable in minor units.
        is_partial_payment:
          type: boolean
          const: true
          description: Always true for this event.
        is_final_payment:
          type: boolean
          const: false
          description: Always false for this event.
        payment_policy:
          $ref: '#/components/schemas/InvoicePaymentPolicy'
          description: Payment acceptance policy of the invoice.
        currency:
          type: string
          description: ISO 4217 currency code.
        provider_tx_id:
          type: string
          description: Provider transaction reference; empty when unavailable.
        payer_name:
          type: string
          description: Payer name; empty when unavailable.
        payer_tax_id:
          type: string
          description: Payer tax ID; empty when unavailable.
        partially_paid_at:
          type: string
          format: date-time
          description: Time of this partial payment; equals the envelope timestamp.
    InvoicePaymentPolicy:
      type: object
      additionalProperties: false
      description: Payment acceptance policy of the invoice.
      required: [allow_different_amount, allow_multiple_payments]
      properties:
        allow_different_amount:
          type: boolean
          description: Whether a payment amount different from the invoice amount is accepted.
        allow_multiple_payments:
          type: boolean
          description: Whether the invoice accepts several payments.
    PaymentIntentExpiredData:
      type: object
      additionalProperties: true
      description: The invoice expired unpaid. Correlate by intent_id; order numbers are not included.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required: [intent_id, merchant_id, account_id, expired_at]
      properties:
        intent_id:
          type: string
          format: uuid
          description: PSP payment intent ID.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        expired_at:
          type: string
          format: date-time
          description: Expiry time; equals the envelope timestamp.
    PaymentIntentCanceledData:
      type: object
      additionalProperties: true
      description: |
        Order references for payment.intent.canceled are projected from the
        original order. Added reference fields are optional for historical
        events and persisted deliveries; empty merchant or provider references
        are valid when absent from the original order. Correlate within the
        account scope by intent_id or merchant_order_id, without requiring a
        provider reference. Historical deliveries are not backfilled or replayed
        automatically.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required: [intent_id, merchant_id, account_id, cancel_reason, canceled_at]
      properties:
        intent_id:
          type: string
          format: uuid
          description: Stable PSP payment intent ID.
        intent_number:
          type: string
          description: PSP payment intent number; empty when unavailable in a historical event.
        invoice_number:
          type: string
          description: Alias of intent_number with the same value.
        merchant_order_id:
          type: string
          description: Original merchant order reference; empty when none was supplied.
        provider_transaction_id:
          type: string
          description: Original provider reference; empty before submission or when unavailable.
        provider_tx_id:
          type: string
          description: Alias of provider_transaction_id with the same value.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        cancel_reason:
          type: string
          description: Cancellation reason.
        canceled_at:
          type: string
          format: date-time
          description: Cancellation time; equals the envelope timestamp.
    TransferCompletedData:
      type: object
      additionalProperties: true
      description: The transfer (payout) succeeded.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required:
        - transfer_id
        - transfer_number
        - merchant_id
        - merchant_account_id
        - account_id
        - amount
        - transferred_amount
        - fee_amount
        - total_amount
        - currency
        - description
        - merchant_order_id
        - provider_transaction_id
        - provider_tx_id
        - beneficiary_info
        - completed_at
      properties:
        transfer_id:
          type: string
          format: uuid
          description: PSP transfer ID.
        transfer_number:
          type: string
          description: PSP transfer number.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        merchant_account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        account_id:
          type: string
          format: uuid
          description: Alias of merchant_account_id with the same value.
        amount:
          type: integer
          format: int64
          description: Transfer principal in minor units.
        transferred_amount:
          type: integer
          format: int64
          description: Amount sent to the beneficiary in minor units.
        fee_amount:
          type: integer
          format: int64
          description: Merchant fee in minor units.
        total_amount:
          type: integer
          format: int64
          description: Total debited from the merchant (principal plus fee) in minor units.
        currency:
          type: string
          description: ISO 4217 currency code.
        description:
          type: string
          description: Transfer description; empty when none was supplied.
        merchant_order_id:
          type: string
          description: Merchant order reference; empty when none was supplied.
        provider_transaction_id:
          type: string
          description: Provider transaction reference; empty when unavailable.
        provider_tx_id:
          type: string
          description: Alias of provider_transaction_id with the same value.
        beneficiary_info:
          type: [object, 'null']
          additionalProperties: true
          description: Beneficiary details submitted with the transfer; null when unavailable.
        e2e_id:
          type: string
          minLength: 1
          description: End-to-end payment identifier; present only when the rail returned one.
        settlement_id:
          type: string
          minLength: 1
          description: Provider settlement reference; present only when available.
        completed_at:
          type: string
          format: date-time
          description: Completion time; equals the envelope timestamp.
    TransferFailedData:
      type: object
      additionalProperties: true
      description: The transfer failed, including risk rejection.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required:
        - transfer_id
        - merchant_id
        - merchant_account_id
        - account_id
        - transfer_number
        - amount
        - currency
        - merchant_order_id
        - failure_reason
        - failure_code
        - failed_at
      properties:
        transfer_id:
          type: string
          format: uuid
          description: PSP transfer ID.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        merchant_account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        account_id:
          type: string
          format: uuid
          description: Alias of merchant_account_id with the same value.
        transfer_number:
          type: string
          description: PSP transfer number.
        amount:
          type: integer
          format: int64
          description: Transfer amount in minor units.
        currency:
          type: string
          description: ISO 4217 currency code.
        merchant_order_id:
          type: string
          description: Merchant order reference; empty when none was supplied.
        failure_reason:
          type: string
          description: Human-readable failure reason.
        failure_code:
          type: string
          description: Failure code, for example RISK_REJECTED.
        failed_at:
          type: string
          format: date-time
          description: Failure time; equals the envelope timestamp.
    TransferReturnedData:
      type: object
      additionalProperties: true
      description: A completed transfer was returned by the receiving bank.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required:
        - transfer_id
        - merchant_id
        - merchant_account_id
        - account_id
        - transfer_number
        - amount
        - currency
        - merchant_order_id
        - returned_amount
        - return_reason
        - returned_at
      properties:
        transfer_id:
          type: string
          format: uuid
          description: PSP transfer ID.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        merchant_account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        account_id:
          type: string
          format: uuid
          description: Alias of merchant_account_id with the same value.
        transfer_number:
          type: string
          description: PSP transfer number.
        amount:
          type: integer
          format: int64
          description: Original transfer amount in minor units.
        currency:
          type: string
          description: ISO 4217 currency code.
        merchant_order_id:
          type: string
          description: Merchant order reference; empty when none was supplied.
        returned_amount:
          type: integer
          format: int64
          description: Cumulative returned amount in minor units.
        return_reason:
          type: string
          description: Return reason.
        returned_at:
          type: string
          format: date-time
          description: Return time; equals the envelope timestamp.
    CreditCardInvoiceCapturedData:
      type: object
      additionalProperties: true
      description: A credit card invoice was captured.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required:
        - invoice_id
        - invoice_number
        - merchant_id
        - merchant_account_id
        - account_id
        - channel_id
        - amount
        - captured_amount
        - paid_amount
        - fee_amount
        - channel_fee
        - net_amount
        - currency
        - description
        - merchant_order_id
        - provider_transaction_id
        - provider_tx_id
        - captured_at
        - completed_at
      properties:
        invoice_id:
          type: string
          format: uuid
          description: PSP credit card invoice ID.
        invoice_number:
          type: string
          description: PSP credit card invoice number.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        merchant_account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        account_id:
          type: string
          format: uuid
          description: Alias of merchant_account_id with the same value.
        channel_id:
          type: string
          format: uuid
          description: PSP channel ID that processed the capture.
        amount:
          type: integer
          format: int64
          description: Invoice amount in minor units.
        captured_amount:
          type: integer
          format: int64
          description: Captured amount in minor units.
        paid_amount:
          type: integer
          format: int64
          description: Alias of captured_amount with the same value.
        fee_amount:
          type: integer
          format: int64
          description: Merchant fee in minor units.
        channel_fee:
          type: integer
          format: int64
          description: Channel fee in minor units.
        net_amount:
          type: integer
          format: int64
          description: Net amount credited to the merchant in minor units.
        currency:
          type: string
          description: ISO 4217 currency code.
        description:
          type: string
          description: Invoice description; empty when none was supplied.
        merchant_order_id:
          type: string
          description: Merchant order reference; empty when none was supplied.
        provider_transaction_id:
          type: string
          description: Provider transaction reference; empty when unavailable.
        provider_tx_id:
          type: string
          description: Alias of provider_transaction_id with the same value.
        captured_at:
          type: string
          format: date-time
          description: Capture time.
        completed_at:
          type: string
          format: date-time
          description: Alias of captured_at with the same value.
    CreditCardInvoice3DSTimeoutData:
      type: object
      additionalProperties: true
      description: 3-D Secure authentication did not complete in time.
      allOf:
        - $ref: '#/components/schemas/ClassifiedMerchantEventData'
      required:
        - invoice_id
        - merchant_id
        - merchant_account_id
        - account_id
        - three_ds_transaction_id
        - timeout_seconds
        - initiated_at
        - timeout_at
      properties:
        invoice_id:
          type: string
          format: uuid
          description: PSP credit card invoice ID.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        merchant_account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        account_id:
          type: string
          format: uuid
          description: Alias of merchant_account_id with the same value.
        three_ds_transaction_id:
          type: string
          description: 3-D Secure transaction ID.
        timeout_seconds:
          type: integer
          description: Configured authentication timeout in seconds.
        initiated_at:
          type: string
          format: date-time
          description: Time 3-D Secure authentication started.
        timeout_at:
          type: string
          format: date-time
          description: Time authentication timed out; equals the envelope timestamp.
    UnclassifiedMerchantEventData:
      type: object
      additionalProperties: true
      description: Merchant event data for event types that do not carry payment classification.
      properties:
        classification_schema_version: false
        classification: false
    RefundCompletedData:
      type: object
      additionalProperties: true
      description: |
        Common refund completion data. The data has no account ID; scope the
        event by the X-Merchant-Account-ID header.
      allOf:
        - $ref: '#/components/schemas/UnclassifiedMerchantEventData'
      required:
        - refund_id
        - merchant_id
        - original_intent_id
        - refunded_amount
        - currency
        - provider_refund_id
        - completed_at
      properties:
        refund_id:
          type: string
          format: uuid
          description: PSP refund ID.
        merchant_id:
          type: string
          format: uuid
          description: Merchant ID.
        original_intent_id:
          type: string
          format: uuid
          description: ID of the refunded payment intent or transfer.
        original_intent_type:
          type: string
          enum: [payment_intent, transfer_intent]
          description: |
            Type of the refunded order. Sent with first deliveries and with
            callbacks rebuilt by the operator refresh-callback path; may be
            absent from refresh-callback bodies stored before that path
            rebuilt the complete event, which are resent unchanged.
        refunded_amount:
          type: integer
          format: int64
          description: Refunded amount in minor units.
        fee_amount:
          type: integer
          format: int64
          description: |
            Refund fee in minor units; 0 when no fee applies. Absent from events
            produced before 2026-09-15 and from refresh-callback bodies stored
            before that path rebuilt the complete event, which are resent
            unchanged.
        currency:
          type: string
          description: ISO 4217 currency code.
        provider_refund_id:
          type: string
          description: Provider refund reference; empty when unavailable.
        completed_at:
          type: string
          format: date-time
          description: Completion time; equals the envelope timestamp.
    PaymentRefundCompletedData:
      type: object
      additionalProperties: true
      description: A refund of a payment intent (invoice) completed.
      allOf:
        - $ref: '#/components/schemas/RefundCompletedData'
      properties:
        original_intent_type:
          type: string
          const: payment_intent
          description: Always payment_intent for this event.
    TransferRefundCompletedData:
      type: object
      additionalProperties: true
      description: |
        A refund of a transfer completed. PSP also sends
        payment.transfer.returned for the original transfer.
      allOf:
        - $ref: '#/components/schemas/RefundCompletedData'
      properties:
        original_intent_type:
          type: string
          const: transfer_intent
          description: Always transfer_intent for this event.
    PaymentRefundFailedData:
      type: object
      additionalProperties: true
      description: |
        A refund failed. Do not wait for this event: PSP does not create first
        deliveries for it. A body of this type can only appear when an operator
        refreshes or redelivers a delivery that was recorded for it earlier.
        Scope it by X-Merchant-Account-ID.
      allOf:
        - $ref: '#/components/schemas/UnclassifiedMerchantEventData'
      required: [refund_id, failure_reason, failure_code, failed_at]
      properties:
        refund_id:
          type: string
          format: uuid
          description: PSP refund ID.
        failure_reason:
          type: string
          description: Failure reason.
        failure_code:
          type: string
          description: Failure code.
        failed_at:
          type: string
          format: date-time
          description: Failure time; equals the envelope timestamp.
    AccountFrozenData:
      type: object
      additionalProperties: true
      description: The merchant account was frozen.
      allOf:
        - $ref: '#/components/schemas/UnclassifiedMerchantEventData'
      required: [account_id, reason, frozen_at]
      properties:
        account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        reason:
          type: string
          description: Freeze reason.
        frozen_at:
          type: string
          format: date-time
          description: Freeze time; equals the envelope timestamp.
    AccountUnfrozenData:
      type: object
      additionalProperties: true
      description: The merchant account was unfrozen.
      allOf:
        - $ref: '#/components/schemas/UnclassifiedMerchantEventData'
      required: [account_id, unfrozen_at]
      properties:
        account_id:
          type: string
          format: uuid
          description: Merchant account ID.
        unfrozen_at:
          type: string
          format: date-time
          description: Unfreeze time; equals the envelope timestamp.
    ResolvedPaymentClassification:
      type: object
      additionalProperties: false
      required:
        - classification_status
        - payment_category
        - payment_method
        - rail_variant
      properties:
        classification_status:
          type: string
          const: resolved
        payment_category:
          type: string
          pattern: '^[a-z0-9]+(?:_[a-z0-9]+)*$'
        payment_method:
          type: string
          pattern: '^[a-z0-9]+(?:_[a-z0-9]+)*$'
          not:
            enum: [america_cash, cashapp, ecashapp]
        rail_variant:
          type: string
          pattern: '^[a-z0-9]+(?:_[a-z0-9]+)*$'
    MerchantSettlementWebhookEnvelope:
      type: object
      additionalProperties: false
      description: |
        Merchant settlement item notification. The body has no `event`,
        `timestamp` or top-level `data` wrapper of the other envelopes;
        `event_type` equals `X-Webhook-Event` and `event_id` equals
        `X-Webhook-Event-ID`. PSP currently produces
        merchant_settlement.completed.v1; the adjusted and reversed variants
        are accepted by the same delivery path.
      required:
        - schema_version
        - event_id
        - event_type
        - occurred_at
        - aggregate_type
        - aggregate_id
        - aggregate_version
        - data
      allOf:
        - if:
            properties:
              event_type: { const: merchant_settlement.completed.v1 }
          then:
            properties:
              data:
                properties:
                  status: { const: settled }
                  source_type: { const: invoice }
        - if:
            properties:
              event_type: { const: merchant_settlement.adjusted.v1 }
          then:
            properties:
              data:
                required: [parent_item_id, relation_type]
                properties:
                  status: { const: adjusted }
                  source_type: { const: adjustment }
                  parent_item_id: { type: string }
                  relation_type: { const: adjustment }
        - if:
            properties:
              event_type: { const: merchant_settlement.reversed.v1 }
          then:
            properties:
              data:
                required: [parent_item_id, relation_type]
                properties:
                  status: { const: reversed }
                  source_type: { const: reversal }
                  parent_item_id: { type: string }
                  relation_type: { const: reversal }
      properties:
        schema_version:
          type: string
          const: '1.0.0'
          description: Body schema version.
        event_id:
          type: string
          format: uuid
          description: Original settlement event ID (UUIDv7); the deduplication key.
        event_type:
          type: string
          enum:
            - merchant_settlement.completed.v1
            - merchant_settlement.adjusted.v1
            - merchant_settlement.reversed.v1
          description: Settlement event type.
        occurred_at:
          type: string
          format: date-time
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$'
          description: Event time in UTC.
        aggregate_type:
          type: string
          const: merchant_settlement_item
          description: Aggregate type; always merchant_settlement_item.
        aggregate_id:
          type: string
          format: uuid
          description: Settlement item ID; equals data.merchant_item_id.
        aggregate_version:
          type: integer
          minimum: 1
          description: Settlement item version that produced the event.
        data:
          $ref: '#/components/schemas/MerchantSettlementEventData'
    MerchantSettlementEventData:
      type: object
      additionalProperties: false
      description: |
        Public settlement item projection. Amounts are non-negative decimal
        strings in minor units, never JSON numbers, and satisfy
        gross_amount = merchant_fee_amount + net_amount.
      required:
        - merchant_item_id
        - merchant_account_id
        - source_type
        - status
        - gross_amount
        - merchant_fee_amount
        - net_amount
        - currency
        - due_at
        - settled_at
        - parent_item_id
        - relation_type
      properties:
        merchant_item_id:
          type: string
          format: uuid
          description: Settlement item ID.
        merchant_account_id:
          type: string
          format: uuid
          description: Merchant account ID; equals X-Merchant-Account-ID.
        source_type:
          type: string
          enum: [invoice, transfer, refund, chargeback, adjustment, reversal]
          description: |
            Source of the settlement item. merchant_settlement.completed.v1 is
            only delivered for invoice items; adjusted and reversed events use
            adjustment and reversal respectively.
        status:
          type: string
          enum: [settled, adjusted, reversed]
          description: Item status; settled, adjusted or reversed for the respective event type.
        gross_amount:
          type: string
          pattern: '^(0|[1-9][0-9]*)$'
          description: Gross amount as a decimal string in minor units.
        merchant_fee_amount:
          type: string
          pattern: '^(0|[1-9][0-9]*)$'
          description: Merchant fee as a decimal string in minor units.
        net_amount:
          type: string
          pattern: '^(0|[1-9][0-9]*)$'
          description: Net amount as a decimal string in minor units.
        currency:
          type: string
          pattern: '^[A-Z]{3}$'
          description: ISO 4217 currency code.
        due_at:
          type: string
          format: date-time
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$'
          description: Time the item became due for settlement, in UTC.
        settled_at:
          type: string
          format: date-time
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{1,9})?Z$'
          description: Time the item was settled, in UTC.
        parent_item_id:
          type: [string, 'null']
          format: uuid
          description: Parent settlement item for adjustments and reversals; null otherwise.
        relation_type:
          type: [string, 'null']
          enum: [adjustment, reversal, null]
          description: Relation to parent_item_id; null when there is no parent.
    WithdrawalStatusWebhookEnvelope:
      type: object
      additionalProperties: false
      description: |
        Flat body sent by the merchant withdrawal workflow when a withdrawal
        completes or fails. status equals the suffix of event_type. The
        optional fields are supported by the sender but are not populated by
        the current withdrawal workflow.
      required: [event_type, withdrawal_id, status, timestamp]
      properties:
        event_type:
          type: string
          enum: [withdrawal.completed, withdrawal.failed]
          description: Withdrawal event type; equals X-Webhook-Event.
        withdrawal_id:
          type: string
          format: uuid
          description: PSP withdrawal ID.
        status:
          type: string
          enum: [completed, failed]
          description: Terminal withdrawal status.
        timestamp:
          type: string
          format: date-time
          description: Workflow time of the status change, UTC with second precision.
        amount:
          type: string
          description: Withdrawal amount as a decimal string; present only when populated.
        currency:
          type: string
          description: ISO 4217 currency code; present only when populated.
        channel_ref:
          type: string
          description: Channel reference; present only when populated.
        e2e_id:
          type: string
          description: End-to-end payment identifier; present only when populated.
        error_code:
          type: string
          description: Failure code; present only when populated.
        error_message:
          type: string
          description: Failure message; present only when populated.
    SettlementStatusWebhookEnvelope:
      type: object
      additionalProperties: false
      description: |
        Flat body sent by the settlement workflow (distinct from the
        merchant_settlement.*.v1 events). status equals the suffix of
        event_type.
      required: [event_type, settlement_id, status, timestamp, net_amount]
      properties:
        event_type:
          type: string
          enum: [settlement.completed, settlement.failed, settlement.rejected, settlement.canceled]
          description: Settlement event type; equals X-Webhook-Event.
        settlement_id:
          type: string
          format: uuid
          description: PSP settlement ID.
        status:
          type: string
          enum: [completed, failed, rejected, canceled]
          description: Settlement status.
        timestamp:
          type: string
          format: date-time
          description: Workflow time of the status change, UTC with second precision.
        net_amount:
          type: string
          pattern: '^-?(0|[1-9][0-9]*)$'
          description: Settlement amount as a decimal string of integer minor units.
        currency:
          type: string
          description: ISO 4217 currency code; omitted when the settlement has no currency.
