openapi: '3.1.0'

info:
  title: Yugo Payments
  description: |
    :::info[Live API]
    All requests run against the live endpoint `https://api.yugo.finance/`. A dedicated sandbox is coming soon.
    :::

    Hosted payment solution enabling merchants to accept payments (payins) from customers and send funds (payouts) to recipients.
    Supports multiple payment rails including crypto, card payments, and open banking for both fiat and cryptocurrency transactions.

    Merchants can track payment status in real-time and receive webhook notifications for all payment events.
  version: 0.1.0
  contact:
    name: Yugo Finance API Support
    email: support@yugo.finance
    url: https://support.yugo.finance
  license:
    name: Proprietary
    url: https://www.yugo.finance/terms-for-partners

servers:
  - url: https://api.yugo.finance/api/v2
    description: Live production server. A dedicated sandbox is coming soon.

security:
  - ApiKeyAuth: []

tags:
  - name: Payins
    description: Accept payments from customers through our hosted checkout experience.
  - name: Payouts
    description: Send funds to recipients via bank transfers or crypto wallets.
  - name: Banks
    description: List available banks for open banking payment methods.
  - name: Payers
    description: Look up Payers who have transacted with you and the payment instruments they have used in the past.
  # - name: Accounts
  #   description: View your account balances across different currencies.
  - name: Webhooks
    description: Receive real-time notifications for payment status changes.

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key for authentication. Contact support to obtain your API key.
    WebhookSignature:
      type: apiKey
      in: header
      name: X-Webhook-Signature
      description: |
        Hex-encoded HMAC-SHA256 signature of the raw request body, keyed with your webhook secret.

        ```
        X-Webhook-Signature = hex( HMAC_SHA256( webhook_secret, raw_request_body ) )
        ```

        Verify the signature on your side before trusting the payload. See the [Webhooks guide](/docs/webhooks#verifying-the-signature) for details and a code sample.

  schemas:
    
    Bank:
      type: object
      properties:
        id:
          $ref: '#/components/schemas/UUID'
        name:
          type: string
          description: Bank name
          examples:
            - Example Bank
        logo_url:
          type: string
          format: uri
          description: URL to the bank's logo image
          examples:
            - 'https://example.com/logos/bank.png'

    # AccountId:
    #   allOf:
    #     - $ref: '#/components/schemas/UUID'
    #     - description: Unique identifier of the Account

    # Account:
    #   type: object
    #   description: A store of value - holds funds in a specific currency
    #   required:
    #     - id
    #     - currency
    #     - available_balance
    #     - reserved_balance
    #   properties:
    #     id:
    #       $ref: '#/components/schemas/AccountId'
    #     label:
    #       type: string
    #       description: Human-readable label for the account
    #       examples:
    #         - EUR Balance
    #         - Bitcoin Wallet
    #     currency:
    #       $ref: '#/components/schemas/Currency'
    #     available_balance:
    #       allOf:
    #         - $ref: '#/components/schemas/MonetaryAmount'
    #         - description: Funds available for immediate use (e.g. payouts)
    #     reserved_balance:
    #       allOf:
    #         - $ref: '#/components/schemas/MonetaryAmount'
    #         - description: Funds temporarily held for pending transactions (e.g. dispute reserves)

    Pagination:
      type: object
      properties:
        page:
          type: integer
          description: Current page number (1-based indexing)
          examples:
            - 1
        page_size:
          type: integer
          description: Number of items returned in this page
          examples:
            - 20
        has_more:
          type: boolean
          description: Whether additional pages are available
          examples:
            - true

    Reference:
      type: string
      maxLength: 36
      description: |
        Merchant system's unique identifier for this transaction (e.g., order ID, invoice number, transaction ID).
        Used to correlate Yugo payments with Merchant's internal records.
      examples:
        - order_123
        - inv_2024_001
        - 123e4567-e89b-12d3-a456-426614174000

    UUID:
      type: string
      format: uuid
      description: Universally unique identifier
      examples:
        - 123e4567-e89b-12d3-a456-426614174000

    PayinId:
      allOf:
        - $ref: '#/components/schemas/UUID'
        - description: Unique identifier of the Payin

    PayoutId:
      allOf:
        - $ref: '#/components/schemas/UUID'
        - description: Unique identifier of the Payout

    InstrumentId:
      allOf:
        - $ref: '#/components/schemas/UUID'
        - description: Unique identifier of a Payer's payment instrument on record, obtained via `GET /payers`

    Timestamp:
      type: string
      format: date-time
      description: '[ISO 8601 timestamp](https://en.wikipedia.org/wiki/ISO_8601)'
      examples:
        - '2024-01-15T14:30:00Z'

    Iban:
      type: string
      description: '[International Bank Account Number](https://en.wikipedia.org/wiki/International_Bank_Account_Number)'
      examples:
        - DE89370400440532013000

    Currency:
      type: string
      description: '[ISO 4217 currency code](https://www.iso.org/iso-4217-currency-codes.html) for fiat currencies or [CoinMarketCap symbol](https://coinmarketcap.com/all/views/all/) for cryptocurrencies'
      examples:
        - EUR
        - BTC
        - USDT

    MonetaryAmount:
      type: string
      pattern: '^[0-9]+(\.[0-9]{1,8})?$'
      description: |
        Numeric value as a string to preserve precision (must be positive).
        Supports up to 8 decimal places for both fiat and cryptocurrency amounts.
      examples:
        - "5.12"
        - "0.0000385"

    MonetaryAmountWithCurrency:
      type: object
      description: Monetary amount with currency
      required:
        - value
        - currency
      properties:
        value:
          $ref: '#/components/schemas/MonetaryAmount'
        currency:
          $ref: '#/components/schemas/Currency'
      examples:
        - value: "5.12"
          currency: EUR
        - value: "0.0000385"
          currency: BTC

    Email:
      type: string
      format: email
      description: Email address
      examples:
        - payer@example.com

    UserDetails:
      type: object
      properties:
        country:
          type: string
          pattern: '^[A-Z]{2}$'
          description: |
            [ISO 3166-1 alpha-2 code](https://www.iso.org/iso-3166-country-codes.html) that sets the initial country selection in Yugo's payment UI.
            This controls which payment methods are initially shown to the Payer/Recipient based on availability in the specified country.
            The Payer/Recipient can change the country selection if needed.
          examples:
            - DE
        language:
          type: string
          pattern: '^[a-z]{2}$'
          description: |
            [ISO 639-1 alpha-2 code](https://www.iso.org/iso-639-language-code)
            pre-selected language for Yugo's UI. The Payee can change this value
          examples:
            - de
        first_name:
          type: string
          description: First name / given name of the Payer/Payee
          examples:
            - John
        last_name:
          type: string
          description: Last name / family name / surname of the Payer/Payee
          examples:
            - Doe
        phone:
          type: string
          pattern: '^\+[0-9]{7,15}$'
          description: Phone number of the Payer/Payee
          examples:
            - '+491234567890'
        address:
          type: string
          description: Address of the Payer/Payee
          examples:
            - '123 Main St, Berlin'

    PayerDetails:
      allOf:
        - type: object
          required:
            - email
          description: |
            Information about the Payer.
            If providing name information, both `first_name` and `last_name` must be provided together.
          properties:
            email:
              $ref: '#/components/schemas/Email'
            is_new:
              type: boolean
              description: Indicates whether the Payer is depositing for the first time within the Merchant's platform (not their first deposit with Yugo).
        - $ref: '#/components/schemas/UserDetails'

    PayerInstrumentOnRecord:
      type: object
      description: Common fields shared by all payment instruments previously used by a Payer
      required:
        - id
        - method
      properties:
        id:
          $ref: '#/components/schemas/InstrumentId'
        method:
          type: string
          description: Discriminator identifying the payment method type of this instrument

    PayerBankAccountInstrumentOnRecord:
      description: A bank account previously used by the Payer
      allOf:
        - $ref: '#/components/schemas/PayerInstrumentOnRecord'
        - type: object
          required:
            - iban
          properties:
            method:
              const: bank_account
            iban:
              type: string
              description: |
                Masked International Bank Account Number. Only the first 4 and last 4 characters are shown; the remaining characters are replaced with `*`.
              examples:
                - 'DE89**************3000'

    PayerCardInstrumentOnRecord:
      description: A card previously used by the Payer
      allOf:
        - $ref: '#/components/schemas/PayerInstrumentOnRecord'
        - type: object
          required:
            - number
            - expiry
          properties:
            method:
              const: card
            number:
              type: string
              description: |
                Masked card number. Only the first 4 and last 4 digits are shown; the remaining digits are replaced with `*`.
              examples:
                - '4111********1234'
            expiry:
              type: string
              pattern: '^(0[1-9]|1[0-2])/[0-9]{2}$'
              description: Card expiry date in `MM/YY` format
              examples:
                - '12/27'

    PaymentInstrument:
      oneOf:
        - $ref: '#/components/schemas/PayerBankAccountInstrumentOnRecord'
        - $ref: '#/components/schemas/PayerCardInstrumentOnRecord'
      discriminator:
        propertyName: method
        mapping:
          bank_account: '#/components/schemas/PayerBankAccountInstrumentOnRecord'
          card: '#/components/schemas/PayerCardInstrumentOnRecord'

    Payer:
      type: object
      description: A Payer who has transacted with the Merchant, with the payment instruments they have used in the past
      required:
        - email
      properties:
        email:
          $ref: '#/components/schemas/Email'
        instruments:
          type: array
          description: Payment instruments previously used by the Payer. Sensitive fields are masked.
          items:
            $ref: '#/components/schemas/PaymentInstrument'

    BankAccountPayinDetails:
      description: |
        Payment via bank account. Choose exactly one of:
        - `BankAccountPayinByBank` — a specific bank is pre-selected via `bank_id`.
        - `BankAccountPayinByIban` — the Payer's bank account is identified via `iban`.
        - `BankAccountPayinByInstrument` — a previously used bank account is reused via `instrument_id`.
        - `BankAccountPayinViaHostedFlow` — the Payer selects a bank on the Yugo-hosted page.
      oneOf:
        - $ref: '#/components/schemas/BankAccountPayinByBank'
        - $ref: '#/components/schemas/BankAccountPayinByIban'
        - $ref: '#/components/schemas/BankAccountPayinByInstrument'
        - $ref: '#/components/schemas/BankAccountPayinViaHostedFlow'

    BankAccountPayinByBank:
      title: Pre-selected bank
      type: object
      description: A specific bank is pre-selected by the Merchant; the Payer authenticates with that bank.
      required:
        - method
        - bank_id
      properties:
        method:
          type: string
          const: bank_account
        bank_id:
          allOf:
            - $ref: '#/components/schemas/UUID'
            - description: Identifier of the bank that will be used. Retrieve available banks via `GET /banks`.
      not:
        anyOf:
          - required: [iban]
          - required: [instrument_id]

    BankAccountPayinByIban:
      title: IBAN
      type: object
      description: The Payer's bank account is identified directly by its IBAN; the Payer authenticates with the bank holding that account.
      required:
        - method
        - iban
      properties:
        method:
          type: string
          const: bank_account
        iban:
          allOf:
            - $ref: '#/components/schemas/Iban'
            - description: International Bank Account Number of the Payer.
      not:
        anyOf:
          - required: [bank_id]
          - required: [instrument_id]

    BankAccountPayinByInstrument:
      title: Instrument on Record
      type: object
      description: Reuse a bank account the Payer has used in the past, skipping bank selection.
      required:
        - method
        - instrument_id
      properties:
        method:
          type: string
          const: bank_account
        instrument_id:
          allOf:
            - $ref: '#/components/schemas/InstrumentId'
            - description: Identifier of the Payer's instrument on record, obtained via `GET /payers`. Must belong to the Payer identified by `payer.email`.
      not:
        anyOf:
          - required: [bank_id]
          - required: [iban]

    BankAccountPayinViaHostedFlow:
      title: Hosted-page selection
      type: object
      description: The Payer selects a bank on the Yugo-hosted payment page.
      required:
        - method
      properties:
        method:
          type: string
          const: bank_account
      not:
        anyOf:
          - required: [bank_id]
          - required: [iban]
          - required: [instrument_id]

    CardPayinDetails:
      type: object
      description: Payment via credit or debit card
      required:
        - method
      properties:
        method:
          type: string
          const: card

    GooglePayDetails:
      type: object
      description: Payment via GooglePay
      required:
        - method
      properties:
        method:
          type: string
          const: google_pay

    ApplePayDetails:
      type: object
      description: Payment via ApplePay
      required:
        - method
      properties:
        method:
          type: string
          const: apple_pay

    CryptoTransferPayinDetails:
      type: object
      description: Payment via cryptocurrency transfer
      required:
        - method
      properties:
        method:
          type: string
          const: crypto_transfer

    PayinIntent:
      type: object
      required:
        - amount
        - return_url
        - payer
      properties:
        amount:
          allOf:
            - $ref: '#/components/schemas/MonetaryAmountWithCurrency'
            - description: Amount the Payer will be charged
        payer:
          $ref: '#/components/schemas/PayerDetails'
        payment:
          oneOf:
            - $ref: '#/components/schemas/BankAccountPayinDetails'
            - $ref: '#/components/schemas/CardPayinDetails'
            - $ref: '#/components/schemas/GooglePayDetails'
            - $ref: '#/components/schemas/ApplePayDetails'
            - $ref: '#/components/schemas/CryptoTransferPayinDetails'
            - $ref: '#/components/schemas/YugoUserDetails'
          discriminator:
            propertyName: method
            mapping:
              bank_account: '#/components/schemas/BankAccountPayinDetails'
              card: '#/components/schemas/CardPayinDetails'
              google_pay: '#/components/schemas/GooglePayDetails'
              apple_pay: '#/components/schemas/ApplePayDetails'
              crypto_transfer: '#/components/schemas/CryptoTransferPayinDetails'
              yugo_wallet: '#/components/schemas/YugoUserDetails'
        settlement:
          oneOf:
            - $ref: '#/components/schemas/YugoBalancePayoutDetails'
            - $ref: '#/components/schemas/BankAccountPayoutDetails'
            - $ref: '#/components/schemas/CryptoTransferPayoutDetails'
          discriminator:
            propertyName: method
            mapping:
              yugo_balance: '#/components/schemas/YugoBalancePayoutDetails'
              bank_account: '#/components/schemas/BankAccountPayoutDetails'
              crypto_transfer: '#/components/schemas/CryptoTransferPayoutDetails'
        reference:
          allOf:
            - $ref: '#/components/schemas/Reference'
            - description: Merchant-defined reference identifier for this Payin
        return_url:
          type: string
          format: uri
          description: URL where the Payer will be redirected after completing or canceling the Payin
          examples:
            - 'https://merchant.com/checkout/123'
        webhook_url:
          type: string
          format: uri
          description: URL where Yugo will send webhook notifications for Payin status changes
          examples:
            - 'https://merchant.com/api/webhooks/checkout/123'

    Payin:
      allOf:
        - type: object
          properties:
            id:
              $ref: '#/components/schemas/PayinId'
            status:
              type: string
              enum:
                - CREATED
                - INITIATED
                - AUTHORIZED
                - DISPUTED
                - SETTLED
                - COMPLETED
                - FAILED
                - EXPIRED
              description: |
                Current status of the Payin. For state transitions, click [here](./docs/payin/states)
              examples:
                - AUTHORIZED
            status_details:
              type: string
              enum:
                - INSUFFICIENT_FUNDS
                - DECLINED_BY_ISSUER
                - INSTRUMENT_INVALID
                - INSTRUMENT_BLOCKED
                - AUTHORIZATION_FAILED
                - DECLINED_BY_PAYER
                - RISK_REJECTED
                - PROVIDER_ERROR
                - OTHER
              description: |
                Additional context for the current `status`, primarily populated when the Payin has `FAILED`. Possible values:
                  - `INSUFFICIENT_FUNDS` — Not enough balance / amount exceeds credit availability.
                  - `DECLINED_BY_ISSUER` — Refused by the card/account issuing entity.
                  - `INSTRUMENT_INVALID` — Instrument unusable: invalid card number, CVV, expiry, or savings bank account used for payments, etc.
                  - `INSTRUMENT_BLOCKED` — Instrument restricted: blocked, lost, stolen or otherwise unusable account/card.
                  - `AUTHORIZATION_FAILED` — Authorization not satisfied: 3DS/SCA failure or timeout, or payer cancelled.
                  - `DECLINED_BY_PAYER` — Payer actively declined or abandoned the payment (e.g. cancelled at the checkout).
                  - `RISK_REJECTED` — Rejected by internal or provider risk/fraud rules.
                  - `PROVIDER_ERROR` — Underlying provider temporarily unavailable or other technical error.
                  - `OTHER`
              examples:
                - INSUFFICIENT_FUNDS
            created_at:
              $ref: '#/components/schemas/Timestamp'
            expires_at:
              allOf:
                - $ref: '#/components/schemas/Timestamp'
                - description: Timestamp when the Payin expires if not completed
            redirect_url:
              type: string
              format: uri
              description: URL where the Merchant should redirect the Payer to continue with the Payin
              examples:
                - 'https://pay.yugo.finance/payin/123e4567-e89b-12d3-a456-426614174000'
        - $ref: '#/components/schemas/PayinIntent'

    PayoutIntent:
      type: object
      required:
        - amount
        - return_url
      properties:
        amount:
          allOf:
            - $ref: '#/components/schemas/MonetaryAmountWithCurrency'
            - description: Amount the Recipient will receive
        recipient:
          $ref: '#/components/schemas/UserDetails'
        payment:
          oneOf:
            - $ref: '#/components/schemas/BankAccountPayoutDetails'
            - $ref: '#/components/schemas/CryptoTransferPayoutDetails'
            - $ref: '#/components/schemas/YugoUserDetails'
          discriminator:
            propertyName: method
            mapping:
              yugo_wallet: '#/components/schemas/YugoUserDetails'
              bank_account: '#/components/schemas/BankAccountPayoutDetails'
              crypto_transfer: '#/components/schemas/CryptoTransferPayoutDetails'
        reference:
          allOf:
            - $ref: '#/components/schemas/Reference'
            - description: Merchant-defined reference identifier for this Payout
        return_url:
          type: string
          format: uri
          description: URL where the Recipient will be redirected after providing payout details or completing the flow
          examples:
            - 'https://merchant.com/withdrawal/123'
        webhook_url:
          type: string
          format: uri
          description: URL where Yugo will send webhook notifications for Payout status changes
          examples:
            - 'https://merchant.com/api/webhooks/withdrawal/123'

    Payout:
      allOf:
        - type: object
          properties:
            id:
              $ref: '#/components/schemas/PayoutId'
            status:
              type: string
              enum:
                - CREATED
                - INITIATED
                - PROCESSING
                - COMPLETED
                - FAILED
                - EXPIRED
              description: |
                Current status of the Payout. For state transitions, click [here](/docs/payout/status-lifecycle)
              examples:
                - COMPLETED
            created_at:
              $ref: '#/components/schemas/Timestamp'
            expires_at:
              allOf:
                - $ref: '#/components/schemas/Timestamp'
                - description: Timestamp when the Payout expires if not completed
            redirect_url:
              type: string
              format: uri
              description: URL where the Merchant should redirect the Recipient to continue with the Payout
              examples:
                - 'https://pay.yugo.finance/payout/123e4567-e89b-12d3-a456-426614174000'
        - $ref: '#/components/schemas/PayoutIntent'

    YugoUserDetails:
      type: object
      description: Payout to a Yugo Wallet user
      required:
        - method
      properties:
        method:
          type: string
          const: yugo_wallet
        email:
          allOf:
            - $ref: '#/components/schemas/Email'
            - description: Email address of the Recipient's Yugo Wallet account

    YugoBalancePayoutDetails:
      type: object
      description: Settlement to merchant's Yugo balance
      required:
        - method
      properties:
        method:
          type: string
          const: yugo_balance

    BankAccountPayoutDetails:
      description: |
        Payout to a bank account. Choose exactly one of:
        - `BankAccountPayoutByIban` — the Merchant provides the Recipient's IBAN.
        - `BankAccountPayoutByInstrument` — the Merchant provides a Yugo system `bank_account` id of the Recipient.
        - `BankAccountPayoutViaHostedFlow` — the Recipient enters bank account details on the Yugo-hosted page.
      oneOf:
        - $ref: '#/components/schemas/BankAccountPayoutViaHostedFlow'
        - $ref: '#/components/schemas/BankAccountPayoutByInstrument'
        - $ref: '#/components/schemas/BankAccountPayoutByIban'

    BankAccountPayoutByIban:
      title: IBAN
      type: object
      description: The Merchant supplies the Recipient's bank account number directly.
      required:
        - method
        - iban
      properties:
        method:
          type: string
          const: bank_account
        iban:
          allOf:
            - $ref: '#/components/schemas/Iban'
            - description: International Bank Account Number of the Recipient.
      not:
        required:
          - instrument_id

    BankAccountPayoutByInstrument:
      title: Instrument on Record
      type: object
      description: Reuse a bank account the Recipient has used in the past as a Payer.
      required:
        - method
        - instrument_id
      properties:
        method:
          type: string
          const: bank_account
        instrument_id:
          allOf:
            - $ref: '#/components/schemas/InstrumentId'
            - description: Identifier of the Recipient's instrument on record, obtained via `GET /payers`.
      not:
        required:
          - iban

    BankAccountPayoutViaHostedFlow:
      title: Hosted-page selection
      type: object
      description: The Recipient chooses their bank account using the Yugo-hosted flow.
      required:
        - method
      properties:
        method:
          type: string
          const: bank_account
      not:
        anyOf:
          - required: [iban]
          - required: [instrument_id]

    CryptoTransferPayoutDetails:
      type: object
      description: Payout to a cryptocurrency wallet address
      required:
        - method
      properties:
        method:
          type: string
          const: crypto_transfer
        address:
          type: string
          description: Cryptocurrency wallet address of the Recipient
          examples:
            - '0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb'
        network:
          type: string
          enum:
            - polygon
          description: Blockchain network where the Recipient's wallet address is located
          examples:
            - polygon

    ProblemDetail:
      type: object
      description: A problem detail object as defined in [RFC 9457](https://datatracker.ietf.org/doc/html/rfc9457)
      properties:
        type:
          type: string
          format: uri
          description: A URI reference that identifies the problem type
          default: about:blank
          examples:
            - https://example.com/probs/out-of-credit
        title:
          type: string
          description: A short, human-readable summary of the problem type
          examples:
            - You do not have enough credit.
        status:
          type: integer
          description: The HTTP status code generated by the origin server for this occurrence of the problem
          minimum: 100
          maximum: 599
          examples:
            - 400
        detail:
          type: string
          description: A human-readable explanation specific to this occurrence of the problem
          examples:
            - Your current balance is 30, but that costs 50.
        instance:
          type: string
          format: uri
          description: A URI reference that identifies the specific occurrence of the problem
          examples:
            - /account/12345/msgs/abc

    ValidationProblemDetail:
      allOf:
        - $ref: '#/components/schemas/ProblemDetail'
        - type: object
          properties:
            errors:
              type: array
              description: List of validation errors
              items:
                type: object
                required:
                  - detail
                  - pointer
                properties:
                  detail:
                    type: string
                    description: Validation error message
                    examples:
                      - must be a positive number
                  pointer:
                    type: string
                    description: JSON Pointer to the field that failed validation
                    examples:
                      - "#/payer/email"

  responses:
    BadRequest:
      description: Request is malformed or contains invalid syntax
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          examples:
            'Bad Request':
              value:
                type: about:blank
                title: Bad Request
                status: 400
                detail: The request was invalid

    Unauthorized:
      description: Missing or invalid authentication credentials
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          examples:
            'Unauthorized':
              value:
                type: about:blank
                title: Unauthorized
                status: 401
                detail: Invalid or missing API key

    Forbidden:
      description: Valid credentials provided but insufficient permissions for the requested operation
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          examples:
            'Forbidden':
              value:
                type: about:blank
                title: Forbidden
                status: 403
                detail: You do not have permission to access this resource

    NotFound:
      description: Requested resource does not exist
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          examples:
            'Resource Not Found':
              value:
                type: about:blank
                title: Not Found
                status: 404
                detail: The requested resource was not found

    ValidationError:
      description: Request validation failed
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ValidationProblemDetail'
          examples:
            'Validation Error':
              value:
                type: https://yugo.finance/problems/validation-error
                title: Validation Error
                status: 422
                detail: Request validation failed
                errors:
                  - detail: must be a positive integer
                    pointer: "#/amount/value"

    InternalServerError:
      description: Unexpected server error occurred
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          examples:
            'Internal Server Error':
              value:
                type: about:blank
                title: Internal Server Error
                status: 500
                detail: An unexpected error occurred

    TooManyRequests:
      description: Too many requests - rate limit exceeded
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetail'
          examples:
            'Too Many Requests':
              value:
                type: about:blank
                title: Too Many Requests
                status: 429
                detail: Rate limit exceeded. Please retry after some time.
#      headers:
#        X-RateLimit-Limit:
#          description: Maximum number of requests allowed per time window
#          schema:
#            type: integer
#          example: 100
#        X-RateLimit-Remaining:
#          description: Number of requests remaining in current time window
#          schema:
#            type: integer
#          example: 0
#        X-RateLimit-Reset:
#          description: Unix timestamp when the rate limit resets
#          schema:
#            type: integer
#          example: 1640995200
#        Retry-After:
#          description: Number of seconds to wait before retrying
#          schema:
#            type: integer
#          example: 60

    PayinList:
      description: Paginated list of Payins
      content:
        application/json:
          schema:
            allOf:
              - type: object
                properties:
                  content:
                    type: array
                    description: Payins in the current page
                    items:
                      $ref: '#/components/schemas/Payin'
              - $ref: '#/components/schemas/Pagination'

    BankList:
      description: Paginated list of banks
      content:
        application/json:
          schema:
            allOf:
              - type: object
                properties:
                  content:
                    type: array
                    description: Banks in the current page
                    items:
                      $ref: '#/components/schemas/Bank'
              - $ref: '#/components/schemas/Pagination'

    # AccountList:
    #   description: Paginated list of Accounts
    #   content:
    #     application/json:
    #       schema:
    #         allOf:
    #           - type: object
    #             properties:
    #               content:
    #                 type: array
    #                 description: Accounts in the current page
    #                 items:
    #                   $ref: '#/components/schemas/Account'
    #           - $ref: '#/components/schemas/Pagination'

    PayerList:
      description: Paginated list of Payers
      content:
        application/json:
          schema:
            allOf:
              - type: object
                properties:
                  content:
                    type: array
                    description: Payers in the current page
                    items:
                      $ref: '#/components/schemas/Payer'
              - $ref: '#/components/schemas/Pagination'

    PayoutList:
      description: Paginated list of Payouts
      content:
        application/json:
          schema:
            allOf:
              - type: object
                properties:
                  content:
                    type: array
                    description: Payouts in the current page
                    items:
                      $ref: '#/components/schemas/Payout'
              - $ref: '#/components/schemas/Pagination'

  parameters:
    PageParam:
      name: page
      in: query
      description: Page number to retrieve (1-based indexing)
      required: false
      schema:
        type: integer
        minimum: 1
        default: 1
      example: 1

    PageSizeParam:
      name: page_size
      in: query
      description: Maximum number of items to return per page
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
      example: 20

    IdempotencyKeyHeader:
      name: Idempotency-Key
      in: header
      description: |
        Unique key to safely retry requests without duplicate operations.
        Use the same key for retries of the same request.
        When reusing an idempotency key, no new object will be created; instead, the previously created object will be returned.

        See the [Idempotency Guide](https://docs.yugo.finance/docs/idempotency) for best practices and examples.
      required: true
      schema:
        type: string
        maxLength: 36
      example: 550e8400-e29b-41d4-a716-446655440000

externalDocs:
  description: Full API documentation
  url: https://docs.yugo.finance

paths:
  /payins:
    get:
      summary: List Payins
      description: |
        Retrieve a paginated list of all Payins for the merchant

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::
      operationId: getPayins
      tags:
        - Payins
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PageSizeParam'
        - name: reference
          in: query
          description: Filter results by merchant-defined reference identifier
          required: false
          schema:
            $ref: '#/components/schemas/Reference'
      responses:
        '200':
          $ref: '#/components/responses/PayinList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

    post:
      summary: Create Payin
      description: |
        Create a new Payin resource - accepting funds from a Payer

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::
      operationId: createPayin
      tags:
        - Payins
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PayinIntent'
      responses:
        '201':
          description: Payin created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payin'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /payins/{id}:
    get:
      summary: Get Payin
      description: |
        Retrieve details of a specific Payin by its unique identifier

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::
      operationId: getPayinById
      tags:
        - Payins
      parameters:
        - name: id
          in: path
          required: true
          description: Unique identifier of the Payin
          schema:
            $ref: '#/components/schemas/PayinId'
      responses:
        '200':
          description: Payin retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payin'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

#  /payins/{id}/refund:
#    post:
#      summary: Refund Payin
#      description: Create a refund for a specific Payin
#      operationId: refundPayin
#      tags:
#        - Payins
#      parameters:
#        - name: id
#          in: path
#          required: true
#          description: Unique identifier of the Payin to refund
#          schema:
#            $ref: '#/components/schemas/PayinId'
#        - $ref: '#/components/parameters/IdempotencyKeyHeader'
#      responses:
#        '202':
#          description: Refund request accepted and is being processed
#          content:
#            application/json:
#              schema:
#                type: object
#        '400':
#          $ref: '#/components/responses/BadRequest'
#        '401':
#          $ref: '#/components/responses/Unauthorized'
#        '403':
#          $ref: '#/components/responses/Forbidden'
#        '404':
#          $ref: '#/components/responses/NotFound'
#        '500':
#          $ref: '#/components/responses/InternalServerError'
#
#  /payins/{id}/events:
#    get:
#      summary: List Payin Events
#      description: 'TODO: Define event schema and structure'
#      operationId: getPayinEvents
#      tags:
#        - Payins
#      parameters:
#        - name: id
#          in: path
#          required: true
#          description: Unique identifier of the Payin
#          schema:
#            $ref: '#/components/schemas/PayinId'
#      responses:
#        '200':
#          description: 'TODO: Define response schema'
#          content:
#            application/json:
#              schema:
#                type: object
#        '400':
#          $ref: '#/components/responses/BadRequest'
#        '401':
#          $ref: '#/components/responses/Unauthorized'
#        '403':
#          $ref: '#/components/responses/Forbidden'
#        '404':
#          $ref: '#/components/responses/NotFound'
#        '500':
#          $ref: '#/components/responses/InternalServerError'

  /payouts:
    get:
      summary: List Payouts
      description: |
        Retrieve a paginated list of all Payouts for the merchant

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::
      operationId: getPayouts
      tags:
        - Payouts
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PageSizeParam'
        - name: reference
          in: query
          description: Filter results by merchant-defined reference identifier
          required: false
          schema:
            $ref: '#/components/schemas/Reference'
      responses:
        '200':
          $ref: '#/components/responses/PayoutList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

    post:
      summary: Create Payout
      description: |
        Create a new Payout resource - sending funds to a Recipient

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::
      operationId: createPayout
      tags:
        - Payouts
      parameters:
        - $ref: '#/components/parameters/IdempotencyKeyHeader'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PayoutIntent'
      responses:
        '201':
          description: Payout created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payout'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/ValidationError'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /payouts/{id}:
    get:
      summary: Get Payout
      description: |
        Retrieve details of a specific Payout by its unique identifier

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::
      operationId: getPayoutById
      tags:
        - Payouts
      parameters:
        - name: id
          in: path
          required: true
          description: Unique identifier of the Payout
          schema:
            $ref: '#/components/schemas/PayoutId'
      responses:
        '200':
          description: Payout retrieved successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Payout'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

#  /payouts/{id}/events:
#    get:
#      summary: List Payout Events
#      description: 'TODO: Define event schema and structure'
#      operationId: getPayoutEvents
#      tags:
#        - Payouts
#      parameters:
#        - name: id
#          in: path
#          required: true
#          description: Unique identifier of the Payout
#          schema:
#            $ref: '#/components/schemas/PayoutId'
#      responses:
#        '200':
#          description: 'TODO: Define response schema'
#          content:
#            application/json:
#              schema:
#                type: object
#        '400':
#          $ref: '#/components/responses/BadRequest'
#        '401':
#          $ref: '#/components/responses/Unauthorized'
#        '403':
#          $ref: '#/components/responses/Forbidden'
#        '404':
#          $ref: '#/components/responses/NotFound'
#        '500':
#          $ref: '#/components/responses/InternalServerError'

  /payers:
    get:
      summary: List Payers
      description: |
        Retrieve a paginated list of Payers who have transacted with the Merchant, along with the payment instruments they have used in the past.

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::

        Sensitive fields on the returned instruments are masked: bank account IBANs and card numbers expose only their first 4 and last 4 characters.
      operationId: getPayers
      tags:
        - Payers
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PageSizeParam'
        - name: email
          in: query
          description: Filter results by Payer email address (exact match)
          required: false
          schema:
            $ref: '#/components/schemas/Email'
      responses:
        '200':
          $ref: '#/components/responses/PayerList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

  /banks:
    get:
      summary: List Banks
      description: |
        Retrieve a paginated list of banks available for open banking payments

        :::info[Live API]
        Requests run against the live endpoint `https://api.yugo.finance/`. A sandbox is coming soon.
        :::
      operationId: getBanks
      tags:
        - Banks
      parameters:
        - $ref: '#/components/parameters/PageParam'
        - $ref: '#/components/parameters/PageSizeParam'
      responses:
        '200':
          $ref: '#/components/responses/BankList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '500':
          $ref: '#/components/responses/InternalServerError'

  # /accounts:
  #   get:
  #     summary: List Accounts
  #     description: Retrieve a paginated list of accounts with their balances
  #     operationId: getAccounts
  #     tags:
  #       - Accounts
  #     parameters:
  #       - $ref: '#/components/parameters/PageParam'
  #       - $ref: '#/components/parameters/PageSizeParam'
  #       - name: currency
  #         in: query
  #         description: Filter results by currency code
  #         required: false
  #         schema:
  #           $ref: '#/components/schemas/Currency'
  #     responses:
  #       '200':
  #         $ref: '#/components/responses/AccountList'
  #       '400':
  #         $ref: '#/components/responses/BadRequest'
  #       '401':
  #         $ref: '#/components/responses/Unauthorized'
  #       '403':
  #         $ref: '#/components/responses/Forbidden'
  #       '429':
  #         $ref: '#/components/responses/TooManyRequests'
  #       '500':
  #         $ref: '#/components/responses/InternalServerError'

webhooks:
  'Payin Status Changed':
    post:
      operationId: payinStatusChanged
      summary: Payin Status Changed
      description: Webhook notification sent when a Payin transitions to a new status
      tags:
        - Webhooks
      security:
        - WebhookSignature: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Payin'

  'Payout Status Changed':
    post:
      operationId: payoutStatusChanged
      summary: Payout Status Changed
      description: Webhook notification sent when a Payout transitions to a new status
      tags:
        - Webhooks
      security:
        - WebhookSignature: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Payout'