openapi: 3.1.0
info:
  title: Better Payment OneAPI
  version: "3.19.93"
  summary: Payment processing, refunds, payouts, checkout sessions, network tokens, and webhooks.
  description: |
    Better Payment **OneAPI** provides endpoints to create payments, manage their
    lifecycle (authorize → capture → refund / reverse), generate hosted checkout
    sessions, manage card-network tokens, and receive asynchronous status
    notifications via webhooks (postbacks).

    All endpoints accept and return `application/json` unless noted otherwise.
    All requests are authenticated using HTTP Basic with your `api_key` as the
    user and `api_password` as the password.

    See the published documentation at https://docs.betterpayment.de for
    end-to-end integration guides, error codes and transaction status reference.
  contact:
    name: Better Payment Support
    url: https://www.betterpayment.de
  license:
    name: Proprietary
    identifier: LicenseRef-Proprietary

servers:
  - url: https://api.betterpayment.de
    description: Production
  - url: https://testapi.betterpayment.de
    description: Test / Sandbox

tags:
  - name: Transactions
    description: Create and manage payment transactions, authorizations, captures, refunds, reversals, payouts, and registrations.
  - name: Checkout
    description: Create hosted checkout sessions where the customer selects a payment method on a Better Payment-hosted page.
  - name: Network Tokens
    description: Provision, retrieve and archive card network tokens (Visa Token Service, Mastercard MDES) for card-on-file processing.
  - name: Webhooks
    description: Asynchronous outbound notifications (postbacks) sent from Better Payment to merchant systems.

security:
  - basicAuth: []

paths:
  /rest/payment:
    post:
      tags: [Transactions]
      summary: Create a payment
      operationId: createPayment
      description: |
        Creates a new payment transaction. Authorization and capture happen in a
        single step — funds are captured immediately on success.

        Use `/rest/authorize` instead if you need to separate authorization from
        capture. The accepted parameter blocks (billing address, redirection
        URLs, cardholder data, wallet cryptogram, POS data, recurring) depend on
        the `payment_type`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentRequest"
            examples:
              cardEcom:
                summary: Card e-commerce (hosted page redirect)
                value:
                  payment_type: cardecom
                  order_id: "122"
                  amount: 15.90
                  currency: EUR
                  postback_url: https://merchant.example.com/postback
                  success_url: https://merchant.example.com/success
                  error_url: https://merchant.example.com/error
                  first_name: John
                  last_name: Doe
                  email: john.doe@email.com
                  address: Rosenthalerstr. 8
                  city: Berlin
                  postal_code: "10178"
                  country: DE
              applePayWithCryptogram:
                summary: Apple Pay (Server-to-Server, decrypted token)
                value:
                  payment_type: applepay
                  order_id: APAY-67890
                  amount: 25.90
                  currency: EUR
                  postback_url: https://merchant.example.com/postback
                  success_url: https://merchant.example.com/success
                  error_url: https://merchant.example.com/error
                  card_number: "4761070000000509"
                  card_holder: John Doe
                  card_expiry_month: "12"
                  card_expiry_year: "2026"
                  threeds_wallet_cryptogram: AgAAAAAABk4DWZ4C28yUQAAAAAA=
                  threeds_wallet_cryptogram_eci: "07"
              posContactless:
                summary: POS card-present (SoftPOS contactless)
                value:
                  payment_type: cardpos
                  order_id: POS-12345678
                  amount: 25.50
                  currency: EUR
                  postback_url: https://merchant.example.com/postback
                  pos_data:
                    type: { terminal_entry_mode: contactless }
                    card:
                      number: "4761739001010010"
                      expiry_month: 12
                      expiry_year: 2027
                      track2_data: 4761739001010010D27121200000000000F
                      emv_data: 9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000
                    terminal:
                      id: "87654321"
                      type: softpos
                      attended: true
                      capabilities: [contactlessChip, onlinePin, noCvm]
              posPinRetry:
                summary: POS retry after `request_pin` (Single Tap)
                value:
                  payment_type: cardpos
                  order_id: POS-12345678
                  amount: 25.50
                  currency: EUR
                  postback_url: https://merchant.example.com/postback
                  pos_data:
                    type:
                      terminal_entry_mode: contactless
                      sequence: subsequent
                    card:
                      number: "4761739001010010"
                      expiry_month: 12
                      expiry_year: 2027
                      track2_data: 4761739001010010D27121200000000000F
                      emv_data: 9F26081234567890ABCDEF9F100706010A03A000009F3602000195050000000000
                    pin_block:
                      format: ISO-0
                      block: D766AAA13ED5CA50
                      zone_id: pos-gateway
                      key_id: "0001"
                    terminal:
                      id: "87654321"
                      type: softpos
                      attended: true
                      capabilities: [contactlessChip, onlinePin, noCvm]
              recurringRepeat:
                summary: Recurring repeat payment using original_transaction_id
                value:
                  payment_type: cardecom
                  order_id: REC-002
                  amount: 9.99
                  currency: EUR
                  postback_url: https://merchant.example.com/postback
                  recurring: 1
                  original_transaction_id: 5e02903b-0fbf-4266-affd-dc58f2749cd1
      responses:
        "200":
          description: Payment created. The response may include a `client_action` requiring follow-up redirect or POST form on the customer's browser.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionResponse"
              examples:
                redirect:
                  summary: Redirect required (e.g. card e-commerce, Wero, iDEAL)
                  value:
                    transaction_id: 88593bcc-d819-4347-84d1-ebfec3806a24
                    payment_type: cardecom
                    status_code: 1
                    status: started
                    order_id: "123000"
                    amount: 15.9
                    included_fees: "0.00"
                    error_code: 0
                    client_action: redirect
                    action_data:
                      url: https://hosted-page.example.com/pay/88593bcc
                completed:
                  summary: Completed instantly (Apple Pay with cryptogram, recurring CC)
                  value:
                    transaction_id: a2c4e6f8-1234-5678-abcd-ef0123456789
                    payment_type: applepay
                    status_code: 3
                    status: completed
                    order_id: APAY-67890
                    included_fees: "0.00"
                    error_code: 0
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/authorize:
    post:
      tags: [Transactions]
      summary: Authorize a payment (without capture)
      operationId: authorizePayment
      description: |
        Reserves funds without capturing them. Use the Capture endpoint to
        capture later, or the Reverse endpoint to release. Accepts the same
        request body as `/rest/payment`.

        Both `/rest/payment` and `/rest/authorize` accept `amount=0` for Card,
        Apple Pay and Google Pay payment methods to perform an account status
        check (or to "save" a card for future use when combined with
        `recurring=1`).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentRequest"
      responses:
        "200":
          description: Authorization created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/capture:
    post:
      tags: [Transactions]
      summary: Capture an authorized transaction
      operationId: captureTransaction
      description: |
        Captures funds from a previously authorized transaction. Partial
        captures are supported as long as the cumulative captured amount does
        not exceed the original authorization.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CaptureRequest"
      responses:
        "200":
          description: Capture processed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CaptureResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/reverse:
    post:
      tags: [Transactions]
      summary: Reverse (cancel) an authorized transaction
      operationId: reverseTransaction
      description: |
        Reverses an authorized transaction that has not yet been captured.
        Partial reversals are supported when the configured acquirer allows
        them. After capture, use `/rest/refund` instead.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ReversalRequest"
      responses:
        "200":
          description: Reversal processed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ReversalResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/refund:
    post:
      tags: [Transactions]
      summary: Refund a captured transaction
      operationId: refundTransaction
      description: |
        Issues a full or partial refund for a captured transaction. Multiple
        refunds are allowed per transaction as long as their combined amount
        does not exceed the original captured amount. Partial refund support
        depends on the payment method.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RefundRequest"
      responses:
        "200":
          description: Refund processed. Status fields reflect the refund object, not the originating transaction.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/RefundResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/payout:
    post:
      tags: [Transactions]
      summary: Send an unreferenced payout
      operationId: createPayout
      description: |
        Sends money from the merchant account to a customer account without
        referencing an existing payment (useful for disbursements, rewards,
        unreferenced refunds). Only specific payment methods support payouts.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PayoutRequest"
      responses:
        "200":
          description: Payout created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PayoutResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/register:
    post:
      tags: [Transactions]
      summary: Register a card for future payments
      operationId: registerCard
      description: |
        Registers card data for future charging without blocking funds. The
        returned `transaction_id` is later used as `original_transaction_id`
        in calls to `/rest/payment`.

        Request and response bodies are identical to `/rest/payment`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentRequest"
      responses:
        "200":
          description: "Registration created. Typically returns `client_action: redirect` so the customer can enter card data on the hosted page."
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TransactionResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/checkouts:
    post:
      tags: [Checkout]
      summary: Create a hosted checkout session
      operationId: createCheckout
      description: |
        Creates a checkout session that returns a hosted payment-page URL.
        Customers can pick from any payment method enabled on the merchant
        account, including Apple Pay and Google Pay.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CheckoutRequest"
      responses:
        "200":
          description: Checkout session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CheckoutResponse"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }

  /rest/transactions:
    get:
      tags: [Transactions]
      summary: List transactions
      operationId: listTransactions
      description: |
        Lists transactions for the authenticated merchant. Defaults to the 50
        most recent transactions; narrow the list using query parameters.
      parameters:
        - in: query
          name: from
          schema: { type: string, format: date-time }
          description: Earliest transaction date (ISO 8601).
          example: "2016-10-05T17:50:28+02:00"
        - in: query
          name: to
          schema: { type: string, format: date-time }
          description: Latest transaction date (ISO 8601).
          example: "2016-10-26T18:00:00+02:00"
        - in: query
          name: status
          schema: { type: string }
          description: Filter by status code, or comma-separated list of status codes (e.g. `2,3`). See `TransactionStatusCode`.
          example: "2,3"
        - in: query
          name: currency
          schema:
            $ref: "#/components/schemas/CurrencyCode"
          description: Filter by 3-letter ISO 4217 currency code.
        - in: query
          name: order_id
          schema: { type: string }
          description: Filter by merchant order ID.
      responses:
        "200":
          description: Array of transactions.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Transaction"
        "401": { $ref: "#/components/responses/Unauthorized" }

  /rest/transactions/{transaction_id}:
    get:
      tags: [Transactions]
      summary: Get transaction details
      operationId: getTransaction
      parameters:
        - $ref: "#/components/parameters/TransactionIdPath"
      responses:
        "200":
          description: A single transaction.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Transaction"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }

  /rest/transactions/{transaction_id}/log:
    get:
      tags: [Transactions]
      summary: Get transaction event log
      operationId: getTransactionEventLog
      description: |
        Returns the chronological list of lifecycle events for a transaction
        (precheck, authorization, capture, refund, postback, etc.). Some
        attributes are not applicable to every event type — for example,
        postback events store amount as zero.
      parameters:
        - $ref: "#/components/parameters/TransactionIdPath"
      responses:
        "200":
          description: Array of transaction events.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TransactionEvent"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }

  /rest/transactions/{transaction_id}/refunds:
    get:
      tags: [Transactions]
      summary: Get transaction refunds
      operationId: getTransactionRefunds
      description: |
        Returns the list of refunds for a given transaction. Some attributes
        are only included if they were defined when creating the refund, such
        as `merchant_refund_id` and `merchant_reference`.

        Depending on the payment processor, refunds may include extra
        attributes — for example, Wero refunds may include `reason_code`,
        `remittance_info` or `wallet_activity_reference`.
      parameters:
        - $ref: "#/components/parameters/TransactionIdPath"
      responses:
        "200":
          description: Array of refunds for the transaction.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TransactionRefund"
              example:
                - created_at: "2026-04-30T11:25:38.982+02:00"
                  refund_id: 2da779fd-fe0a-44c2-8cbc-0a40d5bae89a
                  amount: 2
                  status_code: 1
                  status: successful
                - created_at: "2026-04-30T11:26:02.575+02:00"
                  refund_id: 88c0185f-2703-4757-8f70-948cc58901c4
                  amount: 3.95
                  status_code: 1
                  status: successful
                  merchant_reference: abc123
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }

  /v2/network_tokens:
    post:
      tags: [Network Tokens]
      summary: Create a network token
      operationId: createNetworkToken
      description: |
        Provisions a network token for a given card via the configured
        tokenization provider (Visa Token Service or Mastercard MDES). The
        token is returned with status `requested` (newly created) or `active`
        (already exists for this card and enrollment).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/NetworkTokenCreateRequest"
      responses:
        "200":
          description: Network token created or already active.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NetworkTokenEnvelope"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "400": { $ref: "#/components/responses/BadRequest" }
    get:
      tags: [Network Tokens]
      summary: List network tokens
      operationId: listNetworkTokens
      parameters:
        - in: query
          name: status
          schema: { $ref: "#/components/schemas/NetworkTokenStatus" }
          description: Filter by token status.
        - in: query
          name: network
          schema: { $ref: "#/components/schemas/NetworkTokenNetwork" }
          description: Filter by card network.
        - in: query
          name: created_at[min]
          schema: { type: string, format: date-time }
          description: Earliest creation timestamp (inclusive).
        - in: query
          name: created_at[max]
          schema: { type: string, format: date-time }
          description: Latest creation timestamp (inclusive).
        - in: query
          name: page
          schema: { type: integer, minimum: 1, default: 1 }
        - in: query
          name: per
          schema: { type: integer, minimum: 1, default: 20 }
      responses:
        "200":
          description: Paginated list of network tokens.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NetworkTokenList"
        "401": { $ref: "#/components/responses/Unauthorized" }

  /v2/network_tokens/{id}:
    parameters:
      - $ref: "#/components/parameters/NetworkTokenIdPath"
    get:
      tags: [Network Tokens]
      summary: Get a network token
      operationId: getNetworkToken
      description: Returns a single network token. The latest state is synced from the tokenization provider on read.
      responses:
        "200":
          description: A network token.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/NetworkTokenEnvelope"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }
    delete:
      tags: [Network Tokens]
      summary: Archive a network token
      operationId: archiveNetworkToken
      description: |
        Archives a network token. **Irreversible** — once archived the token
        cannot be used for further transactions. Returns `202 Accepted` with
        an empty body.
      responses:
        "202":
          description: Archive request accepted.
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }

  /v2/network_tokens/{id}/data:
    parameters:
      - $ref: "#/components/parameters/NetworkTokenIdPath"
    get:
      tags: [Network Tokens]
      summary: Get network token data
      operationId: getNetworkTokenData
      description: |
        Returns sensitive token data (token PAN, expiry, PAR). This response
        does **not** include a cryptogram — use the cryptogram endpoint for
        that. Treat the returned `number` like a real card PAN.
      responses:
        "200":
          description: Token data.
          content:
            application/json:
              schema:
                type: object
                required: [result, data]
                properties:
                  result: { type: string, example: OK }
                  data:
                    $ref: "#/components/schemas/NetworkTokenData"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }

  /v2/network_tokens/{id}/cryptogram:
    parameters:
      - $ref: "#/components/parameters/NetworkTokenIdPath"
    post:
      tags: [Network Tokens]
      summary: Create a cryptogram for a network token
      operationId: createNetworkTokenCryptogram
      description: |
        Generates a DSRP or TAVV cryptogram for the referenced network token.
        Cryptograms should be generated for each initial CIT and MIT charge
        and for all subsequent CIT charges.
      responses:
        "200":
          description: Cryptogram created.
          content:
            application/json:
              schema:
                type: object
                required: [result, data]
                properties:
                  result: { type: string, example: OK }
                  data:
                    $ref: "#/components/schemas/NetworkTokenCryptogram"
        "401": { $ref: "#/components/responses/Unauthorized" }
        "404": { $ref: "#/components/responses/NotFound" }

webhooks:
  paymentPostback:
    post:
      tags: [Webhooks]
      summary: Payment status notification
      operationId: paymentPostback
      description: |
        Sent to the merchant's configured `postback_url` whenever a
        transaction reaches a terminal state (completed, declined, etc.) or
        when its status materially changes.

        The request body is `application/json` and is signed with the merchant
        webhook key — see the `Gateway-Webhook-Signature` header below.

        The merchant endpoint must respond with HTTP 200. Any other status
        (or no response at all) triggers a retry every 10 minutes, for up to
        10 attempts in total.
      parameters:
        - in: header
          name: Gateway-Webhook-Signature
          required: true
          schema: { type: string }
          description: Base64-encoded HMAC-SHA256 of the raw request body, signed with the merchant webhook key.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PaymentPostback"
            examples:
              completed:
                summary: Completed payment
                value:
                  transaction_id: d1bf9fdf-7268-406f-9e08-8d5a9540ab97
                  payment_type: wero
                  status_code: 3
                  status: completed
                  order_id: "12345678"
                  message: CAPTURE SETTLED
                  remittance_info: "12345678 - Test Shop"
                  wallet_activity_reference: WARf47ac10b58cc
                  wallet_account_reference: WAC50000aW12
                  payer_location: DE
                  amount: 15.90
                  included_fees: "0.00"
                  external_transaction_id: 0I66TOoXap2bNLZ2m89tm1
                  checksum: 73a93b8a2d5260f592d98e386c4e5784ee551d1c
              declined:
                summary: Declined payment
                value:
                  transaction_id: bfe9cff7-8cd9-4976-9236-21253c1f40c1
                  payment_type: wero
                  status_code: 6
                  status: declined
                  order_id: "123010"
                  message: CAPTURE REJECTED
                  reason_code: AC01
                  wallet_activity_reference: WARf47ac10b58cc
                  wallet_account_reference: WAC50000aW12
                  payer_location: DE
                  amount: 10.00
                  included_fees: "0.00"
                  checksum: d56fe31a1a38e06337672ca781e4cb6f3b83fd11
      responses:
        "200":
          description: Acknowledged. Anything other than 2xx triggers retries.

  refundPostback:
    post:
      tags: [Webhooks]
      summary: Refund status notification
      operationId: refundPostback
      description: |
        Sent to the merchant's configured `postback_url` for refund lifecycle
        events. Same signature, retry, and acknowledgement semantics as the
        payment postback.
      parameters:
        - in: header
          name: Gateway-Webhook-Signature
          required: true
          schema: { type: string }
          description: Base64-encoded HMAC-SHA256 of the raw request body, signed with the merchant webhook key.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RefundPostback"
            examples:
              completed:
                summary: Refund completed
                value:
                  transaction_id: 609c412f-53bf-4185-bdb4-7c34225607a6
                  payment_type: wero
                  status_code: 7
                  status: refunded
                  order_id: "123000"
                  message: REFUND SETTLED
                  refund_remittance_info: "12345678 - Test Shop"
                  refund_wallet_activity_reference: RWARb23dc80e71af
                  payer_location: DE
                  amount: 10.0
                  refund_status_code: 1
                  refund_id: 58dd2ec9-c6b4-40ec-92d2-047d2913b209
                  included_fees: "0.00"
                  checksum: a7227a1ee524d9da88515cb162656db21701cc74
              declined:
                summary: Refund declined
                value:
                  transaction_id: 609c412f-53bf-4185-bdb4-7c34225607a6
                  payment_type: wero
                  status_code: 7
                  status: refunded
                  order_id: "123000"
                  message: REFUND REJECTED
                  refund_reason_code: AC04
                  refund_wallet_activity_reference: RWARb23dc80e71af
                  payer_location: DE
                  amount: 10.0
                  refund_status_code: 5
                  refund_id: 58dd2ec9-c6b4-40ec-92d2-047d2913b209
                  included_fees: "0.00"
                  checksum: a7227a1ee524d9da88515cb162656db21701cc74
      responses:
        "200":
          description: Acknowledged.

  networkTokenPostback:
    post:
      tags: [Webhooks]
      summary: Network token status notification
      operationId: networkTokenPostback
      description: |
        Sent when a network token's status changes (e.g. `requested` → `active`,
        `active` → `suspended`). Body is `application/x-www-form-urlencoded`.

        The destination URL is configured at merchant level (default) or
        per-token via `postback_url` on token creation. If neither is set, no
        postback is sent.

        Failed deliveries are retried up to **10 times**. Each attempt has a
        5-second timeout.
      parameters:
        - in: header
          name: Gateway-Webhook-Signature
          required: true
          schema: { type: string }
          description: Base64-encoded HMAC-SHA256 of the raw request body, signed with the merchant `incoming_key`.
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: "#/components/schemas/NetworkTokenPostback"
            example:
              network_token_id: f47ac10b-58cc-4372-a567-0e02b2c3d479
              merchant_id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
              status: active
              network: visa
              provider: vts
              created_at: "2026-03-31T10:15:22Z"
              updated_at: "2026-03-31T14:31:46Z"
              checksum: f8b7c2d1a4e2d8...
      responses:
        "200":
          description: Acknowledged.

components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
      description: |
        HTTP Basic authentication. Use your `api_key` as the username and your
        `api_password` as the password. Both are issued by Better Payment.

  parameters:
    TransactionIdPath:
      in: path
      name: transaction_id
      required: true
      schema: { type: string, format: uuid }
      description: ID of the transaction.
      example: 07c8b0a4-186f-4b56-a929-17d13b29c695
    NetworkTokenIdPath:
      in: path
      name: id
      required: true
      schema: { type: string, format: uuid }
      description: UUID of the network token.

  responses:
    Unauthorized:
      description: Authentication failed (invalid `api_key` or `api_password`).
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiError"
          example:
            error_code: 144
            message: Unauthorized.
    BadRequest:
      description: Validation error or business rule violation. The `error_code` field identifies the specific cause; see the Errors reference in the docs.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiError"
          example:
            error_code: 125
            message: Invalid or missing return URLs.
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ApiError"
          example:
            error_code: 102
            message: Transaction not found.

  schemas:
    # ---------------------------------------------------------------- Enums
    PaymentType:
      type: string
      description: Identifier of the payment method used in the request.
      enum:
        - cardecom
        - cardpos
        - applepay
        - googlepay
        - ideal
        - pbb
        - wero
      x-enum-descriptions:
        cardecom: Card e-commerce
        cardpos: Card present (POS terminal)
        applepay: Apple Pay
        googlepay: Google Pay
        ideal: iDEAL
        pbb: Pay by Bank (Request to Pay)
        wero: Wero

    CurrencyCode:
      type: string
      description: 3-letter ISO 4217 currency code.
      pattern: "^[A-Z]{3}$"
      example: EUR

    CountryCode:
      type: string
      description: 2-letter ISO 3166-1 alpha-2 country code.
      pattern: "^[A-Z]{2}$"
      example: DE

    TransactionStatus:
      type: string
      description: Textual transaction status. See the Transaction Status reference in the docs for the canonical list.
      enum:
        - started
        - pending
        - completed
        - error
        - canceled
        - declined
        - refunded
        - authorized
        - registered
        - debt_collection
        - debt_paid
        - reversed
        - chargeback
        - factoring
        - debt_declined
        - factoring_declined

    TransactionStatusCode:
      type: integer
      description: |
        Numeric transaction status code. Mapping:
        1 started, 2 pending, 3 completed, 4 error, 5 canceled, 6 declined,
        7 refunded, 8 authorized, 9 registered, 10 debt_collection,
        11 debt_paid, 12 reversed, 13 chargeback, 14 factoring,
        15 debt_declined, 16 factoring_declined.
      enum: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

    ClientAction:
      type: string
      description: Required client-side action after a payment request.
      enum:
        - redirect
        - postForm
      x-enum-descriptions:
        redirect: Redirect the customer to `action_data.url`.
        postForm: Build and submit a POST form to `action_data.url` with the key/value pairs in `action_data.fields`.

    ActionData:
      type: object
      description: Companion to `client_action`. Carries the redirect target, post-form fields, or POS terminal hints depending on the payment method.
      properties:
        url:
          type: string
          format: uri
        fields:
          type: object
          description: Key/value pairs to submit when `client_action` is `postForm`.
          additionalProperties: { type: string }
        terminal_action:
          type: string
          enum: [request_pin, switch_interface]
          description: |
            For POS responses — terminal-side action required before the transaction can complete.
            - `request_pin`: capture cardholder PIN, encrypt it, and retry with `pos_data.pin_block` and `pos_data.type.sequence: "subsequent"`.
            - `switch_interface`: prompt the cardholder to insert the card and retry with `pos_data.type.terminal_entry_mode: "chip"`.
        new_emv_data:
          type: string
          description: |
            For POS chip transactions — issuer-supplied EMV scripts that must be passed back to the
            integrated circuit card (ICC) without modification. Hex-encoded.
          example: 9F26081234567890ABCDEF

    # ------------------------------------------------------ Shared blocks
    BillingAddress:
      type: object
      description: Billing address fields. Required for most payment methods.
      properties:
        address:
          type: string
          maxLength: 255
          description: Street address.
        address2:
          type: string
          maxLength: 255
          description: Second address line.
        city: { type: string, maxLength: 255 }
        postal_code: { type: string, maxLength: 255 }
        state:
          type: string
          maxLength: 255
          description: County, state, or region.
        country: { $ref: "#/components/schemas/CountryCode" }
        first_name: { type: string, maxLength: 255 }
        last_name: { type: string, maxLength: 255 }
        email: { type: string, format: email, maxLength: 255 }
        phone: { type: string, maxLength: 255 }

    RedirectionUrls:
      type: object
      description: Required for hosted-page or redirect-based payment methods.
      properties:
        success_url:
          type: string
          format: uri
          description: Redirect target after a successful transaction. `order_id` and `transaction_id` are appended as query parameters.
        error_url:
          type: string
          format: uri
          description: Redirect target after a failed transaction.

    CardholderData:
      type: object
      description: |
        Card data and 3DS / processing controls. Used for Server-to-Server card
        processing and for unmanaged Apple Pay / Google Pay flows. Server-to-
        Server card processing requires PCI DSS compliance.
      properties:
        card_number: { type: string, description: Full PAN. }
        card_holder: { type: string }
        card_cvv: { type: string, description: 3-digit CVV. }
        card_expiry_year: { type: string, description: 4-digit year. }
        card_expiry_month: { type: string, description: 1–12. }
        card_entry:
          type: string
          enum: [e-commerce, manual, card-on-file, token, token-on-file]
          description: Classification of how the card data was entered.
        charge_order:
          type: string
          enum: [checkout, unspecified, mail, phone, one-click, recurring, ucof, installment, standing-order]
        clearing_mode:
          type: string
          enum: [auto, manual]
          description: Controls clearing. Defaults to `manual` for authorizations and `auto` for payments.
        clear_after:
          type: string
          format: date-time
          description: ISO 8601 cut-off after which the transaction is cleared automatically.
        sca_exemption_request:
          type: string
          enum: [tra, low-value, scp]
          description: Strong Customer Authentication exemption request.
        threeds_authentication_value:
          type: string
          description: Authentication value from the merchant's own 3DS MPI. Must be sent together with `threeds_directory_server_trans_id`.
        threeds_directory_server_trans_id:
          type: string
          description: Directory Server Transaction ID from the merchant's own 3DS MPI.
        threeds_wallet_cryptogram:
          type: string
          description: Cryptogram from a decrypted Apple Pay or Google Pay token.
        threeds_wallet_cryptogram_eci:
          type: string
          description: ECI indicator from the decrypted wallet token.

    RecurringFields:
      type: object
      description: Mark a payment as recurring and (for repeats) link it to the original transaction.
      properties:
        recurring:
          type: integer
          enum: [0, 1]
          description: Set to 1 to flag the payment as recurring.
        original_transaction_id:
          type: string
          format: uuid
          description: Required for repeat recurring payments — the `transaction_id` of the initial recurring transaction or registration.

    PosData:
      type: object
      description: |
        POS / card-present data. Required when `payment_type=cardpos`. See the Card POS
        payment-method guide for end-to-end flow examples.
      required: [type, card, terminal]
      properties:
        type:
          type: object
          required: [terminal_entry_mode]
          properties:
            terminal_entry_mode:
              type: string
              enum: [chip, contactless, magstripe, magstripe-fallback, manual-entry]
              description: How the card was read at the terminal.
            sequence:
              type: string
              enum: [subsequent]
              description: |
                Only valid value is `subsequent`. Send this on the retry call after the previous
                Payment response carried `action_data.terminal_action: "request_pin"` (Mastercard
                Single Tap online-PIN flow).
            clearing_mode:
              type: string
              enum: [auto, manual]
              description: |
                Defaults to `auto` for payments and `manual` for authorize. Use `manual` to support
                post-authorization gratuity (capture with a different final amount).
        card:
          type: object
          required: [number, expiry_month, expiry_year]
          description: |
            Cardholder data. For chip / contactless / magstripe transactions the PAN must still be
            sent here in addition to the raw `track2_data` / `emv_data` bytes.
          properties:
            number:
              type: string
              description: Primary Account Number (PAN).
            expiry_month:
              type: integer
              minimum: 1
              maximum: 12
            expiry_year:
              type: integer
              minimum: 2000
            track2_data:
              type: string
              description: |
                Track2 data from the card. Required when `terminal_entry_mode` is `chip`,
                `contactless`, `magstripe`, or `magstripe-fallback`. Omitted for `manual-entry`.
            emv_data:
              type: string
              description: |
                EMV data from the chip; submit unaltered as received from the terminal.
                Required for chip transactions.
            card_sequence_number:
              type: string
              pattern: "^[0-9]{1,3}$"
              description: Card sequence number if EMV tag 5F34 is personalized on the chip.
        terminal:
          type: object
          required: [id, type, attended, capabilities]
          properties:
            id:
              type: string
              pattern: "^[a-zA-Z0-9]{1,8}$"
              description: Terminal identifier, alphanumeric, 1–8 chars. Issued by Better Payment onboarding.
              example: "87654321"
            type:
              type: string
              enum: [pos, softpos]
              description: |
                `pos` — physical attended/unattended terminal. `softpos` — software-only
                terminal running on a mobile device; `attended` must be `true`.
            attended:
              type: boolean
              description: Whether the terminal is operated by staff. For `softpos`, must be `true`.
            capabilities:
              type: array
              items:
                type: string
                enum:
                  - contactChip
                  - contactlessChip
                  - contactMagStripe
                  - contactlessMagStripe
                  - offlineEncipheredPin
                  - offlinePlaintextPin
                  - onlinePin
                  - signature
                  - keyEntry
                  - noCvm
                  - oneTap
              description: |
                Entry / verification modes the terminal supports. For `type: softpos` only the
                subset `[contactlessChip, onlinePin, signature, noCvm, oneTap]` is permitted.
                If `capabilities` includes `keyEntry` or `signature`, `attended` must be `true`.
        pin_block:
          type: object
          description: |
            Required only when online PIN verification is needed (typically Mastercard Single
            Tap above the contactless CVM limit). When present, all four sub-fields are required.
          required: [format, block, zone_id, key_id]
          properties:
            format:
              type: string
              enum: [ISO-0, ISO-1, ISO-4]
              description: PIN block encoding format. `ISO-0` / `ISO-1` use a 16-hex block; `ISO-4` uses a 32-hex block.
            block:
              type: string
              description: Encrypted PIN block received from the terminal (hex).
            zone_id:
              type: string
              description: Encryption zone identifier, assigned to your terminal during onboarding.
            key_id:
              type: string
              description: Encryption key identifier within the zone, assigned during onboarding.
        allow_partial_approval:
          type: boolean
          default: false
          description: |
            Indicates the terminal supports partial approvals (e.g. for prepaid cards with
            insufficient balance). Visa and Mastercard only. Cannot be combined with cashback.

    # ----------------------------------------------------- Payment request
    PaymentRequest:
      type: object
      description: |
        Unified request body for `/rest/payment`, `/rest/authorize`, and
        `/rest/register`. The `payment_type` selects which optional blocks
        apply — billing address, redirection URLs, cardholder data, wallet
        cryptogram, POS data, recurring.
      required:
        - payment_type
        - order_id
        - amount
        - currency
        - postback_url
      allOf:
        - type: object
          properties:
            payment_type: { $ref: "#/components/schemas/PaymentType" }
            order_id:
              type: string
              maxLength: 255
              description: Alphanumeric merchant order identifier.
            invoice_id:
              type: string
              maxLength: 20
              description: Invoice number (factoring / debt collection).
            invoice_date:
              type: string
              format: date
              description: Invoice date (YYYY-MM-DD).
            customer_id:
              type: string
              maxLength: 40
            merchant_reference:
              type: string
              maxLength: 255
              description: Free-form reference. Effective string length limit varies by payment method (255 max).
            amount:
              type: number
              format: float
              description: Total amount, including shipping and VAT.
              minimum: 0
            shipping_costs:
              type: number
              format: float
            VAT:
              type: number
              format: float
            currency: { $ref: "#/components/schemas/CurrencyCode" }
            postback_url:
              type: string
              format: uri
              description: HTTPS URL where transaction status postbacks will be delivered.
            locale:
              type: string
              description: Language code for hosted-page payment forms (ISO 639-1).
            additional_transaction_data:
              type: string
              description: Free-form metadata returned in postbacks and on transaction queries.
        - $ref: "#/components/schemas/BillingAddress"
        - $ref: "#/components/schemas/RedirectionUrls"
        - $ref: "#/components/schemas/CardholderData"
        - $ref: "#/components/schemas/RecurringFields"
        - type: object
          properties:
            pos_data:
              $ref: "#/components/schemas/PosData"

    # ----------------------------------------------------- Capture/Reverse
    CaptureRequest:
      type: object
      required: [transaction_id]
      properties:
        transaction_id:
          type: string
          format: uuid
        amount:
          type: number
          format: float
          description: When omitted, the full authorized amount is captured. Cannot exceed it.
        vat:
          type: number
          format: float

    CaptureResponse:
      type: object
      properties:
        transaction_id: { type: string, format: uuid }
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
        order_id: { type: string }
        message: { type: string }
        card_last_four: { type: string }
        card_expiry_year: { type: integer }
        card_expiry_month: { type: integer }
        card_brand: { type: string }
        error_code: { type: integer }

    ReversalRequest:
      type: object
      required: [transaction_id]
      properties:
        transaction_id: { type: string, format: uuid }
        amount:
          type: number
          format: float
          description: When omitted, reverses the full authorization. Specify a smaller amount for a partial reversal (when supported by the acquirer).

    ReversalResponse:
      type: object
      properties:
        transaction_id: { type: string, format: uuid }
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
        order_id: { type: string }
        message: { type: string }
        error_code: { type: integer }

    # ------------------------------------------------------------- Refund
    RefundRequest:
      type: object
      required: [transaction_id]
      properties:
        transaction_id: { type: string, format: uuid }
        merchant_reference:
          type: string
          maxLength: 255
        amount:
          type: number
          format: float
          description: When omitted, refunds the full original amount. Combined refunds across multiple calls cannot exceed the captured amount.
        execution_date:
          type: string
          format: date
        comment:
          type: string
          maxLength: 255
          description: Internal-only refund note.

    RefundResponse:
      type: object
      description: Response is attributed to the refund object — `status_code`/`status` reflect the refund, not the original transaction.
      properties:
        transaction_id: { type: string, format: uuid }
        refund_id: { type: string, format: uuid }
        status_code:
          type: integer
          description: Refund status code. 0 STARTED, 1 SUCCESS, 2 ERROR, 3 LOCAL, 4 REVERSED, 5 DECLINED.
          enum: [0, 1, 2, 3, 4, 5]
        status:
          type: string
          description: |
            Textual refund status. Known values include `started`, `successful`,
            `error`, `reversed`, `declined`. Always interpret using
            `status_code` for canonical mapping.
        error_code: { type: integer }

    # ------------------------------------------------------------- Payout
    PayoutRequest:
      type: object
      required: [payment_type, order_id, amount, currency, merchant_reference, postback_url]
      properties:
        payment_type: { $ref: "#/components/schemas/PaymentType" }
        order_id: { type: string, maxLength: 255 }
        amount: { type: number, format: float }
        currency: { $ref: "#/components/schemas/CurrencyCode" }
        merchant_reference: { type: string, maxLength: 255 }
        postback_url: { type: string, format: uri }
        first_name: { type: string, maxLength: 255 }
        last_name: { type: string, maxLength: 255 }
        address: { type: string, maxLength: 255 }
        city: { type: string, maxLength: 255 }
        country: { $ref: "#/components/schemas/CountryCode" }
        postal_code: { type: string, maxLength: 255 }
        email: { type: string, format: email, maxLength: 255 }
        pos_data:
          $ref: "#/components/schemas/PosData"

    PayoutResponse:
      type: object
      properties:
        transaction_id: { type: string, format: uuid }
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
        order_id: { type: string }
        error_code: { type: integer }

    # --------------------------------------------------- Transaction (read)
    TransactionResponse:
      type: object
      description: Response body for `/rest/payment`, `/rest/authorize`, and `/rest/register`.
      properties:
        transaction_id: { type: string, format: uuid }
        payment_type: { $ref: "#/components/schemas/PaymentType" }
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
        order_id: { type: string }
        message: { type: [string, "null"] }
        additional_transaction_data: { type: [string, "null"] }
        amount: { type: number, format: float }
        included_fees: { type: string }
        error_code: { type: integer }
        client_action: { $ref: "#/components/schemas/ClientAction" }
        action_data: { $ref: "#/components/schemas/ActionData" }
        # POS-specific extras returned in some responses
        card_last_four: { type: string }
        card_expiry_year: { type: integer }
        card_expiry_month: { type: integer }
        card_brand: { type: string }
        card_type: { type: string }
        card_country: { type: string }

    Transaction:
      type: object
      description: Persisted transaction representation returned by the listing and details endpoints.
      properties:
        transaction_id: { type: string, format: uuid }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
        amount: { type: number, format: float }
        currency: { $ref: "#/components/schemas/CurrencyCode" }
        order_id: { type: [string, "null"] }
        recurring:
          type: integer
          enum: [0, 1]
        sepa_mandate: { type: [string, "null"] }
        parent_id: { type: [string, "null"] }
        payment_method: { $ref: "#/components/schemas/PaymentType" }
        message: { type: [string, "null"] }
        sepa_msg_id: { type: [string, "null"] }
        captured_amount:
          type: [number, "null"]
          format: float
        additional_transaction_data: { type: [string, "null"] }

    TransactionRefund:
      type: object
      description: A single refund belonging to a transaction.
      properties:
        created_at: { type: string, format: date-time }
        refund_id: { type: string, format: uuid }
        amount: { type: number, format: float }
        status_code:
          type: integer
          description: "Refund status code: 0 Started, 1 Success, 2 Error."
          enum: [0, 1, 2]
        status: { type: string }
        merchant_reference:
          type: string
          description: Merchant reference, if provided when creating the refund.

    TransactionEvent:
      type: object
      properties:
        created_at: { type: string, format: date-time }
        type:
          type: string
          enum: [precheck, authorization, reauthorization, capture, refund, reversal, postback]
        status: { type: integer }
        amount: { type: number, format: float }
        execution_date:
          type: [string, "null"]
          format: date
        message: { type: [string, "null"] }

    # ----------------------------------------------------------- Checkout
    PrefillCustomerInfo:
      type: object
      properties:
        email: { type: string, format: email }
        phone: { type: string }
        company: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        address: { type: string }
        address2: { type: string }
        city: { type: string }
        state: { type: string }
        postal_code: { type: string }
        country: { $ref: "#/components/schemas/CountryCode" }

    CheckoutRequest:
      type: object
      required:
        - merchant_name
        - order_id
        - currency
        - amount
        - total_amount
        - success_url
        - error_url
        - postback_url
      properties:
        merchant_name: { type: string, description: Merchant name displayed on the hosted checkout page. }
        order_id: { type: string }
        reference: { type: string }
        description: { type: string }
        currency: { $ref: "#/components/schemas/CurrencyCode" }
        amount: { type: number, format: float }
        amount_taxes: { type: number, format: float }
        amount_shipping: { type: number, format: float }
        total_amount:
          type: number
          format: float
          description: Total including taxes and shipping.
        collect_dob: { type: integer, enum: [0, 1] }
        collect_phone: { type: integer, enum: [0, 1] }
        collect_gender: { type: integer, enum: [0, 1] }
        collect_shipping_address: { type: integer, enum: [0, 1] }
        collect_billing_address: { type: integer, enum: [0, 1] }
        display_transaction_details: { type: integer, enum: [0, 1] }
        display_manual_payment_instruction_to_customer:
          type: integer
          enum: [0, 1]
        payment_instruction_merchant_account_holder: { type: string }
        payment_instruction_merchant_iban: { type: string }
        payment_instruction_merchant_bic: { type: string }
        success_url: { type: string, format: uri }
        error_url: { type: string, format: uri }
        postback_url: { type: string, format: uri }
        prefill_customer_info:
          $ref: "#/components/schemas/PrefillCustomerInfo"

    CheckoutResponse:
      type: object
      properties:
        checkout_id: { type: string, format: uuid }
        error_code: { type: integer }
        status:
          type: string
          enum: [open, completed, expired]
        client_action: { $ref: "#/components/schemas/ClientAction" }
        action_data: { $ref: "#/components/schemas/ActionData" }

    # -------------------------------------------------- Network tokens
    NetworkTokenStatus:
      type: string
      enum: [requested, active, suspended, failed, archive_pending, archived]

    NetworkTokenNetwork:
      type: string
      enum: [visa, mastercard]

    NetworkTokenCreateRequest:
      type: object
      required: [card_number, expiry_month, expiry_year]
      properties:
        card_number:
          type: string
          description: Full PAN (12–19 digits).
          pattern: "^[0-9]{12,19}$"
        expiry_month:
          type: integer
          minimum: 1
          maximum: 12
        expiry_year:
          type: integer
          description: 4-digit year.
        card_cvv: { type: string, description: 3-digit CVV. }
        card_holder:
          type: string
          maxLength: 120
        email: { type: string, format: email }
        phone: { type: string }
        billing_country: { $ref: "#/components/schemas/CountryCode" }
        billing_city: { type: string }
        billing_line1: { type: string }
        billing_line2: { type: string }
        billing_postal_code:
          type: string
          description: Alphanumeric, no spaces.
        billing_state: { type: string }
        postback_url:
          type: string
          format: uri
          description: HTTPS URL to receive postback notifications for this token. Overrides the merchant-level default.

    NetworkToken:
      type: object
      properties:
        id: { type: string, format: uuid }
        merchant_id: { type: string, format: uuid }
        status: { $ref: "#/components/schemas/NetworkTokenStatus" }
        type:
          type: string
          enum: [merchant]
        network: { $ref: "#/components/schemas/NetworkTokenNetwork" }
        provider:
          type: string
          description: Tokenization provider identifier (e.g. `vts` for Visa Token Service).
        last_token_refresh:
          type: [string, "null"]
          format: date-time
        error:
          type: object
          description: Present only when `status=failed`.
          properties:
            code: { type: string }
            detail: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }

    NetworkTokenEnvelope:
      type: object
      required: [result, data]
      properties:
        result:
          type: string
          example: OK
        data:
          $ref: "#/components/schemas/NetworkToken"

    NetworkTokenList:
      type: object
      required: [result, data_set, metadata, links]
      properties:
        result: { type: string, example: OK }
        data_set:
          type: array
          items:
            $ref: "#/components/schemas/NetworkToken"
        metadata:
          type: object
          properties:
            per_page: { type: integer }
            total_items: { type: integer }
            current_page: { type: integer }
            total_pages: { type: integer }
        links:
          type: object
          properties:
            self: { $ref: "#/components/schemas/Link" }
            first: { $ref: "#/components/schemas/Link" }
            last: { $ref: "#/components/schemas/Link" }
            prev: { $ref: "#/components/schemas/Link" }
            next: { $ref: "#/components/schemas/Link" }

    Link:
      type: object
      properties:
        href:
          type: string
          format: uri

    NetworkTokenData:
      type: object
      properties:
        id: { type: string, format: uuid }
        number:
          type: string
          description: The network token PAN. Treat as sensitive — handle like a real card PAN.
        expiry_month: { type: integer, minimum: 1, maximum: 12 }
        expiry_year: { type: integer }
        payment_account_reference:
          type: string
          description: Payment Account Reference (PAR) — unique identifier for the underlying account.

    NetworkTokenCryptogram:
      type: object
      properties:
        id: { type: string, format: uuid }
        authentication_data:
          type: string
          description: Base64-encoded cryptogram (up to 32 chars).
        pan_sequence_number:
          type: string
          description: PAN sequence number (2 digits).
        track2_equivalent:
          type: string
          description: Track 2 equivalent data (hex-encoded, up to 40 chars).
        created:
          type: string
          format: date-time

    # ------------------------------------------------------ Webhook bodies
    PaymentPostback:
      type: object
      description: |
        Postback delivered to `postback_url` for transaction lifecycle events
        (started, pending, completed, declined, …). Field set varies with the
        event:

        - `reason_code` is only present for declines / errors.
        - `remittance_info` is sent when a Capture becomes settled (Wero only).
        - `wallet_activity_reference`, `wallet_account_reference`, and
          `payer_location` are specific to Wero and only included when available.
        - `captured_amount` and `currency` are sent on capture-action postbacks.
        - `network_token_id` and `network_token_status` are present only when
          the payment was processed via Network Tokenization.
        - Card-* fields are present only for card-based payment methods (`cc`,
          `cardpos`, `applepay`, `googlepay`) once the transaction has masked
          card data available.

        All values are serialized as strings on the wire (form-style encoding)
        — types below describe the logical shape.
      required: [transaction_id, payment_type, status_code, status, checksum]
      properties:
        transaction_id: { type: string, format: uuid }
        payment_type: { $ref: "#/components/schemas/PaymentType" }
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
        order_id: { type: string, maxLength: 255 }
        message: { type: [string, "null"] }
        recurring:
          type: integer
          enum: [0, 1]
          description: Whether the transaction is part of a recurring sequence.
        checkout_id:
          type: string
          format: uuid
          description: Present when the transaction was created from a hosted checkout session.
        currency:
          $ref: "#/components/schemas/CurrencyCode"
        captured_amount:
          type: string
          description: Captured amount (decimal, sent as a string). Present on capture-action postbacks.
        remittance_info:
          type: string
          description: Sent when a Capture becomes settled.
        reason_code:
          type: string
          description: ISO rejection reason code (e.g. AC01) on declines.
        wallet_activity_reference:
          type: string
          description: Wallet activity reference. Specific to Wero. Only included when available.
        wallet_account_reference:
          type: string
          description: Wallet account reference. Specific to Wero. Only included when available.
        payer_location:
          type: string
          description: Payer location. Specific to Wero. Only included when available.
        additional_transaction_data: { type: [string, "null"] }
        amount: { type: number, format: float }
        included_fees: { type: string }
        external_transaction_id:
          type: string
          description: Reference ID assigned by the payment processor / network. Not available for all payment methods.
        network_token_id:
          type: string
          format: uuid
          description: Present only when the payment was processed using Network Tokenization.
        network_token_status:
          $ref: "#/components/schemas/NetworkTokenStatus"
        # Card-* fields, present for card-based payment methods (cc, applepay, googlepay, pos)
        card_last_four: { type: string }
        card_expiry_year: { type: string }
        card_expiry_month: { type: string }
        card_brand: { type: string }
        card_type: { type: string }
        card_country: { type: string }
        checksum:
          type: string
          description: Legacy SHA1-hex checksum of the parameters using the merchant webhook key. The authoritative signature is the `Gateway-Webhook-Signature` header.

    RefundPostback:
      type: object
      description: Postback delivered to `postback_url` for refund lifecycle events.
      required: [transaction_id, payment_type, refund_id, refund_status_code, checksum]
      properties:
        transaction_id: { type: string, format: uuid }
        payment_type: { $ref: "#/components/schemas/PaymentType" }
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
        order_id: { type: string }
        message: { type: [string, "null"] }
        refund_remittance_info:
          type: string
          description: Sent when the refund becomes completed.
        refund_reason_code:
          type: string
          description: ISO rejection reason code for refund transfers (e.g. AC04).
        refund_wallet_activity_reference:
          type: string
          description: Wallet activity reference for the refund. Specific to Wero. Only included when available.
        payer_location:
          type: string
          description: Payer location. Specific to Wero. Only included when available.
        additional_transaction_data: { type: [string, "null"] }
        amount: { type: number, format: float }
        refund_status_code:
          type: integer
          description: 0 STARTED, 1 SUCCESS, 2 ERROR, 3 LOCAL, 4 REVERSED, 5 DECLINED.
          enum: [0, 1, 2, 3, 4, 5]
        refund_id: { type: string, format: uuid }
        included_fees: { type: string }
        checksum: { type: string }

    NetworkTokenPostback:
      type: object
      description: Form-encoded payload delivered when a network token's lifecycle status changes.
      required: [network_token_id, merchant_id, status, checksum]
      properties:
        network_token_id: { type: string, format: uuid }
        merchant_id: { type: string, format: uuid }
        status: { $ref: "#/components/schemas/NetworkTokenStatus" }
        network: { $ref: "#/components/schemas/NetworkTokenNetwork" }
        provider: { type: string }
        error_code:
          type: string
          description: Present only when `status=failed`.
        error_detail:
          type: string
          description: Present only when `status=failed`.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        checksum:
          type: string
          description: SHA1 hex digest of the payload — see signature header for HMAC verification.

    # ---------------------------------------------------------- API errors
    ApiError:
      type: object
      description: |
        Common error envelope. Most synchronous errors are returned with the
        same shape as a successful response but with a non-zero `error_code`
        and a populated `message`.
      properties:
        error_code:
          type: integer
          description: Numeric error code. See the Errors reference in the docs for the full list.
        message:
          type: string
        status_code: { $ref: "#/components/schemas/TransactionStatusCode" }
        status: { $ref: "#/components/schemas/TransactionStatus" }
