{
  "openapi": "3.0.3",
  "info": {
    "title": "International Payment API",
    "version": "1.0",
    "description": "The International Payment API exposes balances, Payment and Payout through\nversioned HTTPS endpoints.\n\nThis file is the machine-readable OpenAPI specification. Authentication, signing,\nmerchant-order idempotency, unknown-result recovery and Webhook handling\nare explained in the developer guide.\n",
    "contact": {
      "name": "Merchant Support"
    },
    "license": {
      "name": "Proprietary"
    }
  },
  "servers": [
    {
      "url": "{apiBaseUrl}",
      "description": "API base URL issued by the platform. Use the sandbox or production value for the target environment.",
      "variables": {
        "apiBaseUrl": {
          "default": "https://api.example.com",
          "description": "Replace this documentation placeholder with the HTTPS API domain issued for the target environment."
        }
      }
    }
  ],
  "security": [
    {
      "apiKeyAuth": []
    }
  ],
  "tags": [
    {
      "name": "Payment",
      "description": "Create and query payment resources."
    },
    {
      "name": "Payout",
      "description": "Create and query payout resources."
    },
    {
      "name": "Account",
      "description": "Read merchant account resources."
    }
  ],
  "paths": {
    "/intl/v1/balance/query": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Query balances",
        "description": "Returns balance snapshots for the merchant's ACTIVE country and currency\naccounts. `country` and `currency` are optional filters: omit both to\nreturn all ACTIVE accounts, send only `country` to return all currencies\nunder that country, send only `currency` to return all countries under\nthat currency, or send both to return the matched account.\n",
        "operationId": "getBalances",
        "parameters": [
          {
            "$ref": "#/components/parameters/AcceptHeader"
          },
          {
            "$ref": "#/components/parameters/ApiKeyHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/SignatureHeader"
          },
          {
            "$ref": "#/components/parameters/CountryQuery"
          },
          {
            "$ref": "#/components/parameters/CurrencyQuery"
          }
        ],
        "responses": {
          "200": {
            "description": "Merchant balance list.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Timestamp": {
                "$ref": "#/components/headers/ResponseTimestamp"
              },
              "Nonce": {
                "$ref": "#/components/headers/ResponseNonce"
              },
              "Signature": {
                "$ref": "#/components/headers/ResponseSignature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BalanceList"
                },
                "examples": {
                  "all": {
                    "$ref": "#/components/examples/balance-list-response"
                  },
                  "byCountry": {
                    "$ref": "#/components/examples/balance-list-country-response"
                  },
                  "byCurrency": {
                    "$ref": "#/components/examples/balance-list-currency-response"
                  },
                  "exact": {
                    "$ref": "#/components/examples/balance-response"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "422": {
            "$ref": "#/components/responses/BusinessRejected"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/GatewayError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/intl/v1/payment/order/create": {
      "post": {
        "tags": [
          "Payment"
        ],
        "summary": "Create Payment order",
        "description": "Create a Payment order and return payer continuation information, such\nas a checkout URL, QR payload or client-side payment parameters. Use\n`status` as the order business lifecycle state. Reusing the same\n`merchantOrderNo` returns the existing order using the immutable snapshot\nsaved from the first accepted create request; a duplicate request never\nmerges or overwrites that snapshot, including `payer` and `customData`. HTTP `200` is returned\nonly when a core order exists, and its `platOrderNo` is the actual\nplatform order number. HTTP `4xx` and `5xx` responses use `ErrorResponse`\nand never contain `platOrderNo`. If order creation cannot be confirmed,\nthe platform returns HTTP `503` with `error.code=ORDER_RESULT_UNKNOWN`.\nQuery with the original `merchantOrderNo`; a safe create retry must use\nthe same `merchantOrderNo` and an unchanged request, never a replacement\norder number or a concurrent create.\n",
        "operationId": "createPaymentOrder",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContentTypeHeader"
          },
          {
            "$ref": "#/components/parameters/AcceptHeader"
          },
          {
            "$ref": "#/components/parameters/ApiKeyHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/SignatureHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentOrderCreateRequest"
              },
              "examples": {
                "virtual": {
                  "$ref": "#/components/examples/payment-order-create"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payment order created or returned by idempotency, with the actual platform order number.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Timestamp": {
                "$ref": "#/components/headers/ResponseTimestamp"
              },
              "Nonce": {
                "$ref": "#/components/headers/ResponseNonce"
              },
              "Signature": {
                "$ref": "#/components/headers/ResponseSignature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentOrder"
                },
                "examples": {
                  "virtual": {
                    "$ref": "#/components/examples/payment-order-response"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/BusinessRejected"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/OrderResultUnknown"
          }
        }
      }
    },
    "/intl/v1/payment/order/query": {
      "get": {
        "tags": [
          "Payment"
        ],
        "summary": "Query Payment order",
        "description": "Query a Payment order by `merchantOrderNo` to confirm the current order\nstatus and upstream reference number. Use `status` as the order\nbusiness lifecycle state. If the order is canceled, use the failure or\ncancellation reason field to inspect the merchant-safe reason.\nPublic `PROCESSING` alone does not\nprove that a payment action is still available: the core Payment may\nalready be terminal while funds processing is still converging.\n`SUCCEEDED` and `CANCELED` orders do not return a payment action.\n",
        "operationId": "getPaymentOrderByMerchantOrderNo",
        "parameters": [
          {
            "$ref": "#/components/parameters/AcceptHeader"
          },
          {
            "$ref": "#/components/parameters/ApiKeyHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/SignatureHeader"
          },
          {
            "$ref": "#/components/parameters/MerchantOrderNoQuery"
          }
        ],
        "responses": {
          "200": {
            "description": "Payment resource.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Timestamp": {
                "$ref": "#/components/headers/ResponseTimestamp"
              },
              "Nonce": {
                "$ref": "#/components/headers/ResponseNonce"
              },
              "Signature": {
                "$ref": "#/components/headers/ResponseSignature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentOrder"
                },
                "examples": {
                  "virtual": {
                    "$ref": "#/components/examples/payment-order-response"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/GatewayError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    },
    "/intl/v1/payout/order/create": {
      "post": {
        "tags": [
          "Payout"
        ],
        "summary": "Create Payout order",
        "description": "Create a Payout order to send funds to the specified recipient account.\nAccepted API calls do not mean the payout has succeeded. Use `status`\nas the order business lifecycle state. Reusing the same\n`merchantOrderNo` returns the existing order using the immutable snapshot\nsaved from the first accepted create request; a duplicate request never\nmerges or overwrites that snapshot, including `customData`. HTTP `200` is returned\nonly when a core order exists, and its `platOrderNo` is the actual\nplatform order number. HTTP `4xx` and `5xx` responses use `ErrorResponse`\nand never contain `platOrderNo`. If order creation cannot be confirmed,\nthe platform returns HTTP `503` with `error.code=ORDER_RESULT_UNKNOWN`.\nQuery with the original `merchantOrderNo`; a safe create retry must use\nthe same `merchantOrderNo` and an unchanged request, never a replacement\norder number or a concurrent create. Apply the same conservative recovery\nafter a timeout, disconnect or unverifiable response.\n",
        "operationId": "createPayout",
        "parameters": [
          {
            "$ref": "#/components/parameters/ContentTypeHeader"
          },
          {
            "$ref": "#/components/parameters/AcceptHeader"
          },
          {
            "$ref": "#/components/parameters/ApiKeyHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/SignatureHeader"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutCreateRequest"
              },
              "examples": {
                "virtual": {
                  "$ref": "#/components/examples/payout-create"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Payout order created or returned by idempotency, with the actual platform order number.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Timestamp": {
                "$ref": "#/components/headers/ResponseTimestamp"
              },
              "Nonce": {
                "$ref": "#/components/headers/ResponseNonce"
              },
              "Signature": {
                "$ref": "#/components/headers/ResponseSignature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                },
                "examples": {
                  "virtual": {
                    "$ref": "#/components/examples/payout-response"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "415": {
            "$ref": "#/components/responses/UnsupportedMediaType"
          },
          "422": {
            "$ref": "#/components/responses/BusinessRejected"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/OrderResultUnknown"
          }
        }
      }
    },
    "/intl/v1/payout/order/query": {
      "get": {
        "tags": [
          "Payout"
        ],
        "summary": "Query Payout order",
        "description": "Query a Payout order by `merchantOrderNo` to confirm the current order\nstatus, recipient summary and upstream reference number. Use `status`\nas the order business lifecycle state. If the order failed, use the\nfailure reason field to inspect the merchant-safe reason.\n",
        "operationId": "getPayoutByMerchantOrderNo",
        "parameters": [
          {
            "$ref": "#/components/parameters/AcceptHeader"
          },
          {
            "$ref": "#/components/parameters/ApiKeyHeader"
          },
          {
            "$ref": "#/components/parameters/TimestampHeader"
          },
          {
            "$ref": "#/components/parameters/NonceHeader"
          },
          {
            "$ref": "#/components/parameters/SignatureHeader"
          },
          {
            "$ref": "#/components/parameters/MerchantOrderNoQuery"
          }
        ],
        "responses": {
          "200": {
            "description": "Payout resource.",
            "headers": {
              "Request-Id": {
                "$ref": "#/components/headers/RequestId"
              },
              "Timestamp": {
                "$ref": "#/components/headers/ResponseTimestamp"
              },
              "Nonce": {
                "$ref": "#/components/headers/ResponseNonce"
              },
              "Signature": {
                "$ref": "#/components/headers/ResponseSignature"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Payout"
                },
                "examples": {
                  "virtual": {
                    "$ref": "#/components/examples/payout-response"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/GatewayError"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          },
          "504": {
            "$ref": "#/components/responses/GatewayTimeout"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKeyAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "Api-Key",
        "description": "API Key used with Timestamp, Nonce and\nSignature headers. HTTP Header names are case-insensitive in\ntransport, while signature payloads use the documented field names\nexactly. API Secrets are server-side\ncredentials and must never be sent to a browser or included in requests.\n"
      }
    },
    "parameters": {
      "ContentTypeHeader": {
        "name": "Content-Type",
        "in": "header",
        "required": true,
        "description": "POST request body media type, fixed as application/json.",
        "schema": {
          "type": "string",
          "enum": [
            "application/json"
          ]
        },
        "example": "application/json"
      },
      "AcceptHeader": {
        "name": "Accept",
        "in": "header",
        "required": true,
        "description": "Response media type expected by the merchant client, fixed as application/json.",
        "schema": {
          "type": "string",
          "enum": [
            "application/json"
          ]
        },
        "example": "application/json"
      },
      "ApiKeyHeader": {
        "name": "Api-Key",
        "in": "header",
        "required": true,
        "description": "Merchant API Key obtained from Merchant Portal.",
        "schema": {
          "type": "string",
          "minLength": 1
        },
        "example": "ik_fixture_000000000000000000"
      },
      "TimestampHeader": {
        "name": "Timestamp",
        "in": "header",
        "required": true,
        "description": "Unix request signing timestamp text in seconds.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]{10,}$"
        },
        "example": "1780272000"
      },
      "NonceHeader": {
        "name": "Nonce",
        "in": "header",
        "required": true,
        "description": "Request random string unique under the same API Key.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "example": "nonce_fixture_001"
      },
      "SignatureHeader": {
        "name": "Signature",
        "in": "header",
        "required": true,
        "description": "Versioned HMAC-SHA256 request signature.",
        "schema": {
          "type": "string",
          "pattern": "^v1=[a-f0-9]{64}$"
        },
        "example": "v1=9f0c6b1e2d3a4f5867b8c9d0e1f2031425364758697a8b9c0d1e2f3041526374"
      },
      "CountryQuery": {
        "name": "country",
        "in": "query",
        "required": false,
        "description": "Optional ISO 3166-1 alpha-2 country filter for balance query.",
        "schema": {
          "$ref": "#/components/schemas/Country"
        },
        "example": "PH"
      },
      "CurrencyQuery": {
        "name": "currency",
        "in": "query",
        "required": false,
        "description": "Optional ISO 4217 currency filter for balance query.",
        "schema": {
          "$ref": "#/components/schemas/Currency"
        },
        "example": "PHP"
      },
      "MerchantOrderNoQuery": {
        "name": "merchantOrderNo",
        "in": "query",
        "required": true,
        "schema": {
          "$ref": "#/components/schemas/MerchantOrderNo"
        },
        "example": "DEMO_PAY_202606010001"
      }
    },
    "headers": {
      "RequestId": {
        "description": "Request-Id request identifier used for support and log correlation.",
        "schema": {
          "type": "string",
          "pattern": "^req_[A-Za-z0-9_-]+$"
        },
        "example": "req_fixture_000000000000000000000001"
      },
      "ResponseTimestamp": {
        "description": "Response signing Unix timestamp text in seconds since 1970-01-01T00:00:00Z; timezone-independent.",
        "schema": {
          "type": "string",
          "pattern": "^[0-9]{10,}$"
        },
        "example": "1780272000"
      },
      "ResponseNonce": {
        "description": "Nonce response random string used in the response signing payload.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 128
        },
        "example": "nonce_fixture_response_001"
      },
      "ResponseSignature": {
        "description": "Signature versioned HMAC-SHA256 response signature of timestamp, nonce and exact response body.",
        "schema": {
          "type": "string",
          "pattern": "^v1=[a-f0-9]{64}$"
        },
        "example": "v1=31d2e7f0a4b5c6988071625344f5e6d7c8b9a0f1122334455667788990aabbcc"
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid parameters, path, query or request body.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "virtual": {
                "$ref": "#/components/examples/error-response"
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "Api-Key, Timestamp, Nonce or Signature authentication failed.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "invalidSignature": {
                "$ref": "#/components/examples/invalid-signature-response"
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "Merchant, credential, scope or product permission rejected the request. Source-IP admission is managed before the application by the platform security group, WAF or API Gateway.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "permissionDenied": {
                "$ref": "#/components/examples/permission-denied-response"
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "The resource or endpoint does not exist for this merchant.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "orderNotFound": {
                "$ref": "#/components/examples/order-not-found-response"
              }
            }
          }
        }
      },
      "Conflict": {
        "description": "The merchant order number conflicts with an existing resource for the\nsame merchant.\n",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "merchantOrderNoConflict": {
                "$ref": "#/components/examples/merchant-order-no-conflict-response"
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "Request body exceeds 64 KiB.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "requestBodyTooLarge": {
                "$ref": "#/components/examples/request-body-too-large-response"
              }
            }
          }
        }
      },
      "UnsupportedMediaType": {
        "description": "POST body is not `application/json` encoded as UTF-8.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "unsupportedMediaType": {
                "$ref": "#/components/examples/unsupported-media-type-response"
              }
            }
          }
        }
      },
      "BusinessRejected": {
        "description": "Business validation rejected the request before a successful result.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "businessRejected": {
                "$ref": "#/components/examples/business-rejected-response"
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Requests are too frequent.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "rateLimited": {
                "$ref": "#/components/examples/rate-limited-response"
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Internal error for a non-create operation. Retry after bounded backoff.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "internalError": {
                "$ref": "#/components/examples/internal-error-response"
              }
            }
          }
        }
      },
      "GatewayError": {
        "description": "Upstream gateway returned an unexpected error or invalid response for a non-create operation.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "gatewayError": {
                "$ref": "#/components/examples/gateway-error-response"
              }
            }
          }
        }
      },
      "Unavailable": {
        "description": "A non-create API or required dependency is temporarily unavailable.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "serviceUnavailable": {
                "$ref": "#/components/examples/service-unavailable-response"
              }
            }
          }
        }
      },
      "OrderResultUnknown": {
        "description": "The platform could not confirm whether this create request produced an\norder. This condition is returned as HTTP 503 with\n`error.code=ORDER_RESULT_UNKNOWN`; the body is an ErrorResponse and never\ncontains `platOrderNo`. Query the same order type with the original\n`merchantOrderNo`. If the order is still not found after bounded backoff,\na safe create retry must use the same `merchantOrderNo` and the exact same\nbusiness request. Never generate a replacement order number or run\nconcurrent create retries.\n",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "unknown": {
                "$ref": "#/components/examples/order-result-unknown-response"
              }
            }
          }
        }
      },
      "GatewayTimeout": {
        "description": "A non-create upstream gateway did not return a result before timeout.",
        "headers": {
          "Request-Id": {
            "$ref": "#/components/headers/RequestId"
          },
          "Timestamp": {
            "$ref": "#/components/headers/ResponseTimestamp"
          },
          "Nonce": {
            "$ref": "#/components/headers/ResponseNonce"
          },
          "Signature": {
            "$ref": "#/components/headers/ResponseSignature"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            },
            "examples": {
              "gatewayTimeout": {
                "$ref": "#/components/examples/gateway-timeout-response"
              }
            }
          }
        }
      }
    },
    "schemas": {
      "Country": {
        "type": "string",
        "description": "ISO 3166-1 alpha-2 country code.",
        "pattern": "^[A-Z]{2}$",
        "example": "PH"
      },
      "Currency": {
        "type": "string",
        "description": "ISO 4217 currency code.",
        "pattern": "^[A-Z]{3}$",
        "example": "PHP"
      },
      "Money": {
        "type": "string",
        "description": "Non-negative amount in major units. Never send a JSON number or\nscientific notation. Precision is defined by the country currency\nscale and merchant-enabled product configuration.\n",
        "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
        "maxLength": 32,
        "example": "100.50"
      },
      "NullableMoney": {
        "type": "string",
        "nullable": true,
        "description": "Non-negative amount in major units, or null when that side of the\neffective product limit is not configured. Precision is defined by\nthe country currency scale and merchant-enabled product configuration.\n",
        "pattern": "^(0|[1-9][0-9]*)(\\.[0-9]+)?$",
        "maxLength": 32,
        "example": "100.50"
      },
      "PositiveMoney": {
        "type": "string",
        "description": "Amount greater than zero in major units. Never send a JSON number or\nscientific notation. For create requests, precision is determined by\nthe selected productCode and its configured transaction currency.\n",
        "pattern": "^(?:0\\.[0-9]*[1-9][0-9]*|[1-9][0-9]*(?:\\.[0-9]+)?)$",
        "maxLength": 32,
        "example": "100.50"
      },
      "Amount": {
        "type": "object",
        "description": "Amount and transaction currency.",
        "additionalProperties": false,
        "required": [
          "value",
          "currency"
        ],
        "properties": {
          "value": {
            "$ref": "#/components/schemas/Money"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          }
        }
      },
      "PositiveAmount": {
        "type": "object",
        "description": "Positive amount value for create requests. The transaction currency is derived from productCode.",
        "additionalProperties": false,
        "required": [
          "value"
        ],
        "properties": {
          "value": {
            "$ref": "#/components/schemas/PositiveMoney"
          }
        }
      },
      "ProductCode": {
        "type": "string",
        "description": "Stable platform product code enabled for the merchant. The value is\nassigned by the platform product catalog and can indicate the country,\ncurrency and business direction for readability. For create requests, productCode\ndetermines the transaction currency and allowed amount precision, but\ncallers must still treat it as an opaque catalog code and must not\nassemble or parse it themselves.\n",
        "minLength": 1,
        "maxLength": 32,
        "pattern": "^[A-Z0-9_]+$",
        "example": "PH_PHP_PAYMENT_QRPH_GCASH"
      },
      "MerchantOrderNo": {
        "type": "string",
        "description": "Merchant-side unique order number. It must be unique under the same merchant number and is used for idempotency when creating an order.",
        "minLength": 5,
        "maxLength": 32,
        "example": "DEMO_PAY_202606010001"
      },
      "PlatformOrderNo": {
        "type": "string",
        "description": "Actual platform order number created by the core transaction system.\nTreat it as an opaque reconciliation identifier: its format and prefix\ndo not identify the order type. It is present in HTTP 200 order\nresponses and Webhook order payloads, and is never included in an\nErrorResponse. Both historical identifiers and 24-character identifiers are valid.\nPreserve the exact string; never convert it to a number or route by its characters.\n",
        "minLength": 1,
        "maxLength": 32,
        "example": "PHI112606010000000001001"
      },
      "ReferenceNo": {
        "type": "string",
        "description": "Upstream payment-network, payment-institution or recipient-institution reference number used to match payer receipts or recipient bank investigation results to the order. It is not the merchant order number, platform order number or channel order number.",
        "minLength": 1,
        "maxLength": 64,
        "example": "REF-20260601-0001"
      },
      "CustomData": {
        "type": "object",
        "description": "Merchant-defined key-value pairs echoed on the order resource and terminal Webhook event. It is for merchant correlation only and is not used for idempotency, lookup, routing, settlement or risk decisions. On an idempotent duplicate create, the platform returns the immutable customData snapshot saved from the first accepted request; a later request never merges or overwrites it. Use lowerCamelCase keys with at most 40 characters and string values with at most 256 characters. Do not send API keys or secrets, Webhook secrets, signatures, authentication tokens, bank card numbers, full recipient bank or wallet account numbers, identity numbers, phone numbers, email addresses or other sensitive data.",
        "maxProperties": 20,
        "x-property-name-pattern": "^[a-z][A-Za-z0-9]{0,39}$",
        "additionalProperties": {
          "type": "string",
          "maxLength": 256
        },
        "example": {
          "cartId": "CART-10001",
          "customerRef": "CUST-90001"
        }
      },
      "Balance": {
        "type": "object",
        "description": "Balance snapshot for one ACTIVE merchant country and currency account.",
        "additionalProperties": false,
        "required": [
          "country",
          "currency",
          "availableAmount",
          "pendingAmount",
          "frozenAmount",
          "updateTime"
        ],
        "properties": {
          "country": {
            "$ref": "#/components/schemas/Country"
          },
          "currency": {
            "$ref": "#/components/schemas/Currency"
          },
          "availableAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "pendingAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "frozenAmount": {
            "$ref": "#/components/schemas/Money"
          },
          "updateTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the balance snapshot was generated; returned as a timezone-independent JSON number.",
            "minimum": 0
          }
        }
      },
      "BalanceList": {
        "type": "object",
        "description": "Balance query response. An empty balances array means no ACTIVE account matched the filters.",
        "additionalProperties": false,
        "required": [
          "balances"
        ],
        "properties": {
          "balances": {
            "type": "array",
            "description": "Balance snapshots matched by the optional country and currency filters.",
            "items": {
              "$ref": "#/components/schemas/Balance"
            }
          }
        }
      },
      "PaymentOrderCreateRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "merchantOrderNo",
          "productCode",
          "amount",
          "orderDescription"
        ],
        "properties": {
          "merchantOrderNo": {
            "$ref": "#/components/schemas/MerchantOrderNo"
          },
          "productCode": {
            "$ref": "#/components/schemas/ProductCode"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveAmount"
          },
          "orderDescription": {
            "type": "string",
            "description": "Merchant-facing order or product description. If the selected checkout, wallet or channel supports displaying an order description, this value may be shown to the payer. Do not include sensitive data.",
            "minLength": 1,
            "maxLength": 128
          },
          "payer": {
            "$ref": "#/components/schemas/PaymentOrderPayer"
          },
          "customData": {
            "$ref": "#/components/schemas/CustomData"
          }
        }
      },
      "PaymentOrderPayer": {
        "type": "object",
        "description": "Payer contact information for a Payment order. Send this object when the merchant integration needs to attach payer contact data. Responses and Webhooks may return payerSummary when payer contact data is available.",
        "additionalProperties": false,
        "properties": {
          "email": {
            "type": "string",
            "format": "email",
            "minLength": 3,
            "maxLength": 254,
            "description": "Optional payer email address.",
            "example": "payer@example.com"
          },
          "phone": {
            "type": "string",
            "minLength": 6,
            "maxLength": 25,
            "pattern": "^\\+?[0-9][0-9 ()-]{5,24}$",
            "description": "Optional payer phone number. Internationalized loose format is accepted; digits may include a leading plus sign, spaces, hyphens or parentheses.",
            "example": "+639171234567"
          }
        }
      },
      "PayoutCreateRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "merchantOrderNo",
          "productCode",
          "amount",
          "recipient"
        ],
        "properties": {
          "merchantOrderNo": {
            "$ref": "#/components/schemas/MerchantOrderNo"
          },
          "productCode": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProductCode"
              }
            ],
            "example": "PH_PHP_PAYOUT_INSTANT"
          },
          "amount": {
            "$ref": "#/components/schemas/PositiveAmount"
          },
          "recipient": {
            "$ref": "#/components/schemas/Recipient"
          },
          "customData": {
            "$ref": "#/components/schemas/CustomData"
          }
        }
      },
      "Recipient": {
        "type": "object",
        "description": "Recipient account information for a bank-account payout.",
        "additionalProperties": false,
        "required": [
          "bankCode",
          "accountName",
          "accountNo"
        ],
        "properties": {
          "bankCode": {
            "type": "string",
            "description": "Recipient bank code enabled for the selected payout product. Use only values from the supported bank-code catalog.",
            "minLength": 1,
            "maxLength": 20
          },
          "accountName": {
            "type": "string",
            "description": "Recipient account holder name to match the receiving account.",
            "minLength": 1,
            "maxLength": 64
          },
          "accountNo": {
            "type": "string",
            "minLength": 1,
            "maxLength": 50,
            "description": "Recipient bank or wallet account number. PH bank-account products currently allow at most 25 characters."
          }
        }
      },
      "PaymentOrder": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "platOrderNo",
          "merchantOrderNo",
          "status",
          "productCode",
          "country",
          "amount",
          "createTime",
          "updateTime"
        ],
        "properties": {
          "platOrderNo": {
            "$ref": "#/components/schemas/PlatformOrderNo"
          },
          "merchantOrderNo": {
            "$ref": "#/components/schemas/MerchantOrderNo"
          },
          "status": {
            "type": "string",
            "description": "Current business lifecycle status of the Payment.",
            "enum": [
              "PROCESSING",
              "SUCCEEDED",
              "CANCELED"
            ]
          },
          "failReason": {
            "$ref": "#/components/schemas/FailReason"
          },
          "productCode": {
            "$ref": "#/components/schemas/ProductCode"
          },
          "country": {
            "$ref": "#/components/schemas/Country"
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "referenceNo": {
            "$ref": "#/components/schemas/ReferenceNo"
          },
          "nextAction": {
            "$ref": "#/components/schemas/NextAction"
          },
          "payerSummary": {
            "$ref": "#/components/schemas/PayerSummary"
          },
          "customData": {
            "$ref": "#/components/schemas/CustomData"
          },
          "createTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the Payment was created; returned as a timezone-independent JSON number.",
            "minimum": 0
          },
          "updateTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the current Payment status became effective; returned as a timezone-independent JSON number.",
            "minimum": 0
          }
        }
      },
      "Payout": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "platOrderNo",
          "merchantOrderNo",
          "status",
          "productCode",
          "country",
          "amount",
          "createTime",
          "updateTime"
        ],
        "properties": {
          "platOrderNo": {
            "$ref": "#/components/schemas/PlatformOrderNo"
          },
          "merchantOrderNo": {
            "$ref": "#/components/schemas/MerchantOrderNo"
          },
          "status": {
            "type": "string",
            "description": "Current business lifecycle status of the Payout.",
            "enum": [
              "PROCESSING",
              "SUCCEEDED",
              "FAILED"
            ]
          },
          "failReason": {
            "$ref": "#/components/schemas/FailReason"
          },
          "productCode": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProductCode"
              }
            ],
            "example": "PH_PHP_PAYOUT_INSTANT"
          },
          "country": {
            "$ref": "#/components/schemas/Country"
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "referenceNo": {
            "$ref": "#/components/schemas/ReferenceNo"
          },
          "recipientSummary": {
            "$ref": "#/components/schemas/RecipientSummary"
          },
          "customData": {
            "$ref": "#/components/schemas/CustomData"
          },
          "createTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the Payout was created; returned as a timezone-independent JSON number.",
            "minimum": 0
          },
          "updateTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the current Payout status became effective; returned as a timezone-independent JSON number.",
            "minimum": 0
          }
        }
      },
      "FailReason": {
        "type": "string",
        "description": "Merchant-safe failure or cancellation reason. Returned when the order status is FAILED or CANCELED; omitted for PROCESSING and SUCCEEDED.",
        "maxLength": 256
      },
      "NextAction": {
        "type": "object",
        "description": "Checkout or channel continuation information returned with a Payment order when the payer needs a redirect, QR code or client-side payment parameters.",
        "additionalProperties": false,
        "required": [
          "type"
        ],
        "properties": {
          "type": {
            "type": "string",
            "description": "Action discriminator.",
            "enum": [
              "REDIRECT",
              "QR_CODE",
              "PAY_PARAMS"
            ]
          },
          "redirectUrl": {
            "type": "string",
            "format": "uri",
            "description": "URL where the payer completes the required redirect action. Returned when type is REDIRECT."
          },
          "qrCode": {
            "type": "string",
            "description": "Channel-generated QR code raw text returned when type is QR_CODE.\nRender this UTF-8 text as a QR image. When a wallet's official\ndeeplink specification accepts a QR payload parameter, URL-encode\nthe UTF-8 value exactly once after verifying the API response\nsignature. The platform limit is 4096 UTF-8 bytes.\n"
          },
          "payParams": {
            "type": "object",
            "description": "Channel or SDK parameters used by the merchant client to invoke payment. Returned when type is PAY_PARAMS.",
            "additionalProperties": true
          },
          "expireTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the action expires; returned as a timezone-independent JSON number.",
            "minimum": 0
          }
        }
      },
      "RecipientSummary": {
        "type": "object",
        "description": "Masked recipient account summary for merchant reconciliation and support.",
        "additionalProperties": false,
        "required": [
          "bankCode",
          "accountName",
          "accountNoLast4"
        ],
        "properties": {
          "bankCode": {
            "type": "string",
            "description": "Recipient bank code.",
            "maxLength": 20
          },
          "accountName": {
            "type": "string",
            "description": "Recipient account holder name.",
            "maxLength": 64
          },
          "accountNoLast4": {
            "type": "string",
            "description": "Last four characters of the recipient account number. The full account number is never returned.",
            "minLength": 1,
            "maxLength": 4
          }
        }
      },
      "PayerSummary": {
        "type": "object",
        "description": "Payer contact summary for merchant reconciliation and support. Returned when payer contact data was accepted and available. Full payer phone values are never returned.",
        "additionalProperties": false,
        "minProperties": 1,
        "properties": {
          "email": {
            "type": "string",
            "description": "Payer email address returned when accepted and available.",
            "maxLength": 254,
            "example": "payer@example.com"
          },
          "phoneLast4": {
            "type": "string",
            "description": "Last four digits of the payer phone number. The full phone number is never returned.",
            "minLength": 1,
            "maxLength": 4,
            "example": "4567"
          }
        }
      },
      "PaymentWebhookOrder": {
        "type": "object",
        "description": "Terminal Payment order status carried by a Payment Webhook event.",
        "additionalProperties": false,
        "required": [
          "platOrderNo",
          "merchantOrderNo",
          "status",
          "productCode",
          "country",
          "amount",
          "createTime",
          "updateTime"
        ],
        "properties": {
          "platOrderNo": {
            "$ref": "#/components/schemas/PlatformOrderNo"
          },
          "merchantOrderNo": {
            "$ref": "#/components/schemas/MerchantOrderNo"
          },
          "status": {
            "type": "string",
            "description": "Current terminal Payment business status.",
            "enum": [
              "SUCCEEDED",
              "CANCELED"
            ]
          },
          "failReason": {
            "$ref": "#/components/schemas/FailReason"
          },
          "productCode": {
            "$ref": "#/components/schemas/ProductCode"
          },
          "country": {
            "$ref": "#/components/schemas/Country"
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "referenceNo": {
            "$ref": "#/components/schemas/ReferenceNo"
          },
          "payerSummary": {
            "$ref": "#/components/schemas/PayerSummary"
          },
          "customData": {
            "$ref": "#/components/schemas/CustomData"
          },
          "createTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the order was created; returned as a timezone-independent JSON number.",
            "minimum": 0
          },
          "updateTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the current notified order status became effective; returned as a timezone-independent JSON number.",
            "minimum": 0
          }
        }
      },
      "PayoutWebhookOrder": {
        "type": "object",
        "description": "Terminal Payout order status carried by a Payout Webhook event.",
        "additionalProperties": false,
        "required": [
          "platOrderNo",
          "merchantOrderNo",
          "status",
          "productCode",
          "country",
          "amount",
          "createTime",
          "updateTime"
        ],
        "properties": {
          "platOrderNo": {
            "$ref": "#/components/schemas/PlatformOrderNo"
          },
          "merchantOrderNo": {
            "$ref": "#/components/schemas/MerchantOrderNo"
          },
          "status": {
            "type": "string",
            "description": "Current terminal Payout business status.",
            "enum": [
              "SUCCEEDED",
              "FAILED"
            ]
          },
          "failReason": {
            "$ref": "#/components/schemas/FailReason"
          },
          "productCode": {
            "allOf": [
              {
                "$ref": "#/components/schemas/ProductCode"
              }
            ],
            "example": "PH_PHP_PAYOUT_INSTANT"
          },
          "country": {
            "$ref": "#/components/schemas/Country"
          },
          "amount": {
            "$ref": "#/components/schemas/Amount"
          },
          "referenceNo": {
            "$ref": "#/components/schemas/ReferenceNo"
          },
          "recipientSummary": {
            "$ref": "#/components/schemas/RecipientSummary"
          },
          "customData": {
            "$ref": "#/components/schemas/CustomData"
          },
          "createTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the order was created; returned as a timezone-independent JSON number.",
            "minimum": 0
          },
          "updateTime": {
            "type": "integer",
            "format": "int64",
            "description": "Unix timestamp in seconds since 1970-01-01T00:00:00Z when the current notified order status became effective; returned as a timezone-independent JSON number.",
            "minimum": 0
          }
        }
      },
      "PaymentWebhookEvent": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "eventId",
          "eventType",
          "merchantNo",
          "order"
        ],
        "properties": {
          "eventId": {
            "type": "string",
            "description": "Stable event ID used for notification deduplication.",
            "pattern": "^evt_[A-Za-z0-9_-]+$"
          },
          "eventType": {
            "type": "string",
            "description": "Stable terminal event type used to route business handling.",
            "enum": [
              "PAYMENT_SUCCEEDED",
              "PAYMENT_CANCELED"
            ]
          },
          "merchantNo": {
            "type": "string",
            "description": "Merchant number that owns the notified order.",
            "minLength": 1,
            "maxLength": 32
          },
          "order": {
            "$ref": "#/components/schemas/PaymentWebhookOrder"
          }
        }
      },
      "PayoutWebhookEvent": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "eventId",
          "eventType",
          "merchantNo",
          "order"
        ],
        "properties": {
          "eventId": {
            "type": "string",
            "description": "Stable event ID used for notification deduplication.",
            "pattern": "^evt_[A-Za-z0-9_-]+$"
          },
          "eventType": {
            "type": "string",
            "description": "Stable terminal event type used to route business handling.",
            "enum": [
              "PAYOUT_SUCCEEDED",
              "PAYOUT_FAILED"
            ]
          },
          "merchantNo": {
            "type": "string",
            "description": "Merchant number that owns the notified order.",
            "minLength": 1,
            "maxLength": 32
          },
          "order": {
            "$ref": "#/components/schemas/PayoutWebhookOrder"
          }
        }
      },
      "WebhookEvent": {
        "oneOf": [
          {
            "$ref": "#/components/schemas/PaymentWebhookEvent"
          },
          {
            "$ref": "#/components/schemas/PayoutWebhookEvent"
          }
        ]
      },
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "$ref": "#/components/schemas/Error"
          }
        }
      },
      "Error": {
        "type": "object",
        "description": "Structured merchant-safe error details.",
        "additionalProperties": false,
        "required": [
          "code",
          "message"
        ],
        "properties": {
          "code": {
            "type": "string",
            "description": "Stable uppercase machine-readable error code.",
            "pattern": "^[A-Z][A-Z0-9_]*$",
            "example": "PARAMETER_INVALID"
          },
          "message": {
            "type": "string",
            "description": "Merchant-safe English explanation."
          }
        }
      }
    },
    "examples": {
      "WebhookEvent": {
        "$ref": "#/components/examples/webhook-event"
      },
      "PaymentWebhookEvent": {
        "$ref": "#/components/examples/webhook-event"
      },
      "PayoutWebhookEvent": {
        "$ref": "#/components/examples/webhook-payout-event"
      },
      "balance-list-response": {
        "summary": "All balances",
        "value": {
          "balances": [
            {
              "country": "PH",
              "currency": "PHP",
              "availableAmount": "25000.00",
              "pendingAmount": "125.50",
              "frozenAmount": "0.00",
              "updateTime": 1780272000
            },
            {
              "country": "ID",
              "currency": "IDR",
              "availableAmount": "1000000",
              "pendingAmount": "0",
              "frozenAmount": "0",
              "updateTime": 1780272000
            }
          ]
        }
      },
      "balance-list-country-response": {
        "summary": "Balances filtered by country",
        "value": {
          "balances": [
            {
              "country": "PH",
              "currency": "PHP",
              "availableAmount": "25000.00",
              "pendingAmount": "125.50",
              "frozenAmount": "0.00",
              "updateTime": 1780272000
            }
          ]
        }
      },
      "balance-list-currency-response": {
        "summary": "Balances filtered by currency",
        "value": {
          "balances": [
            {
              "country": "PH",
              "currency": "PHP",
              "availableAmount": "25000.00",
              "pendingAmount": "125.50",
              "frozenAmount": "0.00",
              "updateTime": 1780272000
            }
          ]
        }
      },
      "balance-response": {
        "summary": "Virtual PHP balance",
        "value": {
          "balances": [
            {
              "country": "PH",
              "currency": "PHP",
              "availableAmount": "25000.00",
              "pendingAmount": "125.50",
              "frozenAmount": "0.00",
              "updateTime": 1780272000
            }
          ]
        }
      },
      "error-response": {
        "summary": "Invalid amount example",
        "value": {
          "error": {
            "code": "PARAMETER_INVALID",
            "message": "amount.value must be a positive decimal string."
          }
        }
      },
      "invalid-signature-response": {
        "summary": "Invalid request signature",
        "value": {
          "error": {
            "code": "INVALID_SIGNATURE",
            "message": "Signature is invalid."
          }
        }
      },
      "permission-denied-response": {
        "summary": "Permission denied",
        "value": {
          "error": {
            "code": "PERMISSION_DENIED",
            "message": "Merchant or credential does not have permission for this operation."
          }
        }
      },
      "business-rejected-response": {
        "summary": "Business rejected",
        "value": {
          "error": {
            "code": "BUSINESS_REJECTED",
            "message": "Business request was rejected."
          }
        }
      },
      "rate-limited-response": {
        "summary": "Requests are too frequent",
        "value": {
          "error": {
            "code": "FREQUENCY_LIMITED",
            "message": "Requests are too frequent."
          }
        }
      },
      "internal-error-response": {
        "summary": "Internal error",
        "value": {
          "error": {
            "code": "INTERNAL_ERROR",
            "message": "Internal server error."
          }
        }
      },
      "gateway-error-response": {
        "summary": "Gateway error",
        "value": {
          "error": {
            "code": "GATEWAY_ERROR",
            "message": "Upstream gateway returned an invalid response."
          }
        }
      },
      "service-unavailable-response": {
        "summary": "Service unavailable",
        "value": {
          "error": {
            "code": "SERVICE_UNAVAILABLE",
            "message": "API service is temporarily unavailable."
          }
        }
      },
      "gateway-timeout-response": {
        "summary": "Gateway timeout",
        "value": {
          "error": {
            "code": "GATEWAY_TIMEOUT",
            "message": "Upstream gateway timed out."
          }
        }
      },
      "payment-order-create": {
        "summary": "Synthetic QR Payment request; use PH_PHP_PAYMENT_QRPH_GCASH only after the platform enables it for the merchant",
        "value": {
          "merchantOrderNo": "DEMO_PAY_202606010001",
          "productCode": "PH_PHP_PAYMENT_QRPH_GCASH",
          "amount": {
            "value": "100.50"
          },
          "orderDescription": "Virtual order",
          "payer": {
            "email": "payer@example.com",
            "phone": "+639171234567"
          },
          "customData": {
            "cartId": "CART-10001",
            "customerRef": "CUST-90001"
          }
        }
      },
      "payment-order-response": {
        "summary": "Virtual Payment with a checkout redirect",
        "value": {
          "platOrderNo": "PHI112606010000000001001",
          "merchantOrderNo": "DEMO_PAY_202606010001",
          "status": "PROCESSING",
          "productCode": "PH_PHP_PAYMENT_QRPH_GCASH",
          "country": "PH",
          "amount": {
            "value": "100.50",
            "currency": "PHP"
          },
          "nextAction": {
            "type": "REDIRECT",
            "redirectUrl": "https://checkout.example.com/session/fixture-001",
            "expireTime": 1780275600
          },
          "payerSummary": {
            "email": "payer@example.com",
            "phoneLast4": "4567"
          },
          "customData": {
            "cartId": "CART-10001",
            "customerRef": "CUST-90001"
          },
          "createTime": 1780272000,
          "updateTime": 1780272000
        }
      },
      "merchant-order-no-conflict-response": {
        "summary": "Merchant order number conflict",
        "value": {
          "error": {
            "code": "MERCHANT_ORDER_NO_CONFLICT",
            "message": "merchantOrderNo already exists with different business values."
          }
        }
      },
      "request-body-too-large-response": {
        "summary": "Request body too large",
        "value": {
          "error": {
            "code": "REQUEST_BODY_TOO_LARGE",
            "message": "Request body exceeds 64 KiB."
          }
        }
      },
      "unsupported-media-type-response": {
        "summary": "Unsupported media type",
        "value": {
          "error": {
            "code": "UNSUPPORTED_MEDIA_TYPE",
            "message": "Content-Type header must be application/json."
          }
        }
      },
      "order-result-unknown-response": {
        "summary": "Order creation result unknown",
        "value": {
          "error": {
            "code": "ORDER_RESULT_UNKNOWN",
            "message": "Order creation result is unknown. Query with the original merchantOrderNo; retry only with the same merchantOrderNo and unchanged request."
          }
        }
      },
      "order-not-found-response": {
        "summary": "Order not found",
        "value": {
          "error": {
            "code": "ORDER_NOT_FOUND",
            "message": "Payment or payout order was not found."
          }
        }
      },
      "payout-create": {
        "summary": "Create a virtual bank payout",
        "value": {
          "merchantOrderNo": "DEMO_PAYOUT_202606010001",
          "productCode": "PH_PHP_PAYOUT_INSTANT",
          "amount": {
            "value": "500.00"
          },
          "recipient": {
            "bankCode": "DEMO_BANK",
            "accountName": "Demo Recipient",
            "accountNo": "0000000001"
          },
          "customData": {
            "batchId": "BATCH-20260601",
            "employeeRef": "EMP-90001"
          }
        }
      },
      "payout-response": {
        "summary": "Virtual Payout in processing",
        "value": {
          "platOrderNo": "PHO112606010000000001001",
          "merchantOrderNo": "DEMO_PAYOUT_202606010001",
          "status": "PROCESSING",
          "productCode": "PH_PHP_PAYOUT_INSTANT",
          "country": "PH",
          "amount": {
            "value": "500.00",
            "currency": "PHP"
          },
          "recipientSummary": {
            "bankCode": "DEMO_BANK",
            "accountName": "Demo Recipient",
            "accountNoLast4": "0001"
          },
          "customData": {
            "batchId": "BATCH-20260601",
            "employeeRef": "EMP-90001"
          },
          "createTime": 1780272000,
          "updateTime": 1780272000
        }
      },
      "webhook-event": {
        "summary": "Virtual Payment success event",
        "value": {
          "eventId": "evt_fixture_001",
          "eventType": "PAYMENT_SUCCEEDED",
          "merchantNo": "MCH_FIXTURE_001",
          "order": {
            "platOrderNo": "PHI112606010000000001001",
            "merchantOrderNo": "DEMO_PAY_202606010001",
            "status": "SUCCEEDED",
            "productCode": "PH_PHP_PAYMENT_QRPH_GCASH",
            "country": "PH",
            "amount": {
              "value": "100.50",
              "currency": "PHP"
            },
            "referenceNo": "REF-20260601-0001",
            "payerSummary": {
              "email": "payer@example.com",
              "phoneLast4": "4567"
            },
            "customData": {
              "cartId": "CART-10001",
              "customerRef": "CUST-90001"
            },
            "createTime": 1780272000,
            "updateTime": 1780275600
          }
        }
      },
      "webhook-payout-event": {
        "summary": "Virtual Payout success event",
        "value": {
          "eventId": "evt_fixture_payout_001",
          "eventType": "PAYOUT_SUCCEEDED",
          "merchantNo": "MCH_FIXTURE_001",
          "order": {
            "platOrderNo": "PHO112606010000000001001",
            "merchantOrderNo": "DEMO_PAYOUT_202606010001",
            "status": "SUCCEEDED",
            "productCode": "PH_PHP_PAYOUT_INSTANT",
            "country": "PH",
            "amount": {
              "value": "500.00",
              "currency": "PHP"
            },
            "referenceNo": "REF-20260601-9001",
            "recipientSummary": {
              "bankCode": "DEMO_BANK",
              "accountName": "Demo Recipient",
              "accountNoLast4": "0001"
            },
            "customData": {
              "batchId": "BATCH-20260601",
              "employeeRef": "EMP-90001"
            },
            "createTime": 1780272000,
            "updateTime": 1780275600
          }
        }
      }
    }
  },
  "x-error-codes": [
    {
      "code": "INVALID_REQUEST",
      "httpStatus": 400
    },
    {
      "code": "INVALID_JSON",
      "httpStatus": 400
    },
    {
      "code": "PARAMETER_INVALID",
      "httpStatus": 400
    },
    {
      "code": "PARAMETER_MISSING",
      "httpStatus": 400
    },
    {
      "code": "AMOUNT_FORMAT_INVALID",
      "httpStatus": 400
    },
    {
      "code": "INVALID_API_KEY",
      "httpStatus": 401
    },
    {
      "code": "INVALID_SIGNATURE",
      "httpStatus": 401
    },
    {
      "code": "TIMESTAMP_INVALID",
      "httpStatus": 401
    },
    {
      "code": "NONCE_INVALID",
      "httpStatus": 401
    },
    {
      "code": "NONCE_REPLAYED",
      "httpStatus": 401
    },
    {
      "code": "PERMISSION_DENIED",
      "httpStatus": 403
    },
    {
      "code": "PRODUCT_NOT_ENABLED",
      "httpStatus": 403
    },
    {
      "code": "NOT_FOUND",
      "httpStatus": 404
    },
    {
      "code": "ORDER_NOT_FOUND",
      "httpStatus": 404
    },
    {
      "code": "MERCHANT_ORDER_NO_CONFLICT",
      "httpStatus": 409
    },
    {
      "code": "REQUEST_BODY_TOO_LARGE",
      "httpStatus": 413
    },
    {
      "code": "UNSUPPORTED_MEDIA_TYPE",
      "httpStatus": 415
    },
    {
      "code": "BUSINESS_REJECTED",
      "httpStatus": 422
    },
    {
      "code": "INSUFFICIENT_BALANCE",
      "httpStatus": 422
    },
    {
      "code": "AMOUNT_LIMIT_EXCEEDED",
      "httpStatus": 422
    },
    {
      "code": "AMOUNT_PRECISION_INVALID",
      "httpStatus": 422
    },
    {
      "code": "BANK_UNSUPPORTED",
      "httpStatus": 422
    },
    {
      "code": "PRODUCT_UNSUPPORTED",
      "httpStatus": 422
    },
    {
      "code": "COUNTRY_UNSUPPORTED",
      "httpStatus": 422
    },
    {
      "code": "CURRENCY_UNSUPPORTED",
      "httpStatus": 422
    },
    {
      "code": "RECIPIENT_INVALID",
      "httpStatus": 422
    },
    {
      "code": "FREQUENCY_LIMITED",
      "httpStatus": 429
    },
    {
      "code": "INTERNAL_ERROR",
      "httpStatus": 500
    },
    {
      "code": "GATEWAY_ERROR",
      "httpStatus": 502
    },
    {
      "code": "ORDER_RESULT_UNKNOWN",
      "httpStatus": 503
    },
    {
      "code": "SERVICE_UNAVAILABLE",
      "httpStatus": 503
    },
    {
      "code": "GATEWAY_TIMEOUT",
      "httpStatus": 504
    }
  ]
}
