openapi: 3.1.0
info:
  title: GMPay Edge Merchant API
  version: 1.0.0
  description: GMPay is the primary merchant protocol. EPay is a compatibility adapter over the same order service.
servers:
  - url: https://pay.example.com
paths:
  /payments/gmpay/v1/order/create-transaction:
    post:
      operationId: createGmpayTransaction
      summary: Create a GMPay transaction
      description: Accepts JSON or form data. Sign all non-empty fields except signature by sorting key=value pairs by key, joining them with &, appending the API Secret, and calculating lowercase MD5.
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: "#/components/schemas/GmpayCreateRequest" }
          application/x-www-form-urlencoded:
            schema: { $ref: "#/components/schemas/GmpayCreateRequest" }
      responses:
        "200":
          description: Transaction created
          content:
            application/json:
              schema: { $ref: "#/components/schemas/GmpayCreateResponse" }
        "400": { $ref: "#/components/responses/GatewayError" }
        "401": { $ref: "#/components/responses/GatewayError" }
        "429": { $ref: "#/components/responses/GatewayError" }
        "500": { $ref: "#/components/responses/GatewayError" }
        "503": { $ref: "#/components/responses/GatewayError" }
      callbacks:
        orderNotification:
          '{$request.body#/notify_url}':
            post:
              summary: GMPay order notification
              description: The signature is lowercase MD5 of the sorted non-empty callback fields plus the same API Secret. Return plain text ok with HTTP 200.
              requestBody:
                required: true
                content:
                  application/json:
                    schema: { $ref: "#/components/schemas/GmpayNotification" }
              responses:
                "200": { description: Plain text ok acknowledgement }
  /payments/epay/v1/order/create-transaction/submit.php:
    get:
      operationId: createEpayTransactionByQuery
      summary: Create an EPay-compatible transaction
      parameters:
        - { $ref: "#/components/parameters/EpayPid" }
        - { $ref: "#/components/parameters/EpayMoney" }
        - { $ref: "#/components/parameters/EpayOrderNo" }
        - { $ref: "#/components/parameters/EpayNotifyUrl" }
        - { $ref: "#/components/parameters/EpayReturnUrl" }
        - { $ref: "#/components/parameters/EpayName" }
        - { $ref: "#/components/parameters/EpayType" }
        - { $ref: "#/components/parameters/EpaySign" }
        - { $ref: "#/components/parameters/EpaySignType" }
      responses:
        "200":
          description: Created; open data.payment_url to enter the unified checkout
          content:
            application/json:
              schema: { $ref: "#/components/schemas/GatewaySuccess" }
        "400": { $ref: "#/components/responses/GatewayError" }
        "401": { $ref: "#/components/responses/GatewayError" }
    post:
      operationId: createEpayTransactionByForm
      summary: Create an EPay-compatible transaction
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema: { $ref: "#/components/schemas/EpayCreateRequest" }
      responses:
        "200":
          description: Created; open data.payment_url to enter the unified checkout
          content:
            application/json:
              schema: { $ref: "#/components/schemas/GatewaySuccess" }
        "400": { $ref: "#/components/responses/GatewayError" }
        "401": { $ref: "#/components/responses/GatewayError" }
components:
  parameters:
    EpayPid: { name: pid, in: query, required: true, schema: { type: string } }
    EpayMoney: { name: money, in: query, required: true, schema: { type: string, pattern: "^(?!0(?:\\.0+)?$)(?:0|[1-9]\\d*)(?:\\.\\d{1,8})?$" } }
    EpayOrderNo: { name: out_trade_no, in: query, required: true, schema: { type: string, maxLength: 128 } }
    EpayNotifyUrl: { name: notify_url, in: query, required: true, schema: { type: string, format: uri } }
    EpayReturnUrl: { name: return_url, in: query, required: false, schema: { type: string, format: uri } }
    EpayName: { name: name, in: query, required: false, schema: { type: string, maxLength: 500 } }
    EpayType: { name: type, in: query, required: false, description: alipay creates a selectable order; asset.network selects a payment method., schema: { type: string } }
    EpaySign: { name: sign, in: query, required: true, schema: { type: string, pattern: "^[0-9a-f]{32}$" } }
    EpaySignType: { name: sign_type, in: query, required: false, schema: { const: MD5 } }
  responses:
    GatewayError:
      description: Gateway error
      content:
        application/json:
          schema: { $ref: "#/components/schemas/GatewayEnvelope" }
  schemas:
    OrderStatus:
      type: string
      enum: [pending, confirming, partially_paid, paid, overpaid, expired, cancelled, failed, refunded]
    GmpayCreateRequest:
      type: object
      required: [pid, order_id, currency, amount, notify_url, signature]
      properties:
        pid: { type: string, description: API credential PID }
        order_id: { type: string, minLength: 1, maxLength: 128 }
        currency: { type: string, minLength: 3, maxLength: 3 }
        token: { type: string, pattern: "^[A-Za-z0-9_-]{2,20}$", description: Omit together with network to let checkout select a payment method. }
        network: { type: string, pattern: "^[A-Za-z0-9-]{2,32}$", description: Omit together with token to let checkout select a payment method. }
        amount: { type: string, pattern: "^(?!0(?:\\.0+)?$)(?:0|[1-9]\\d*)(?:\\.\\d{1,8})?$" }
        notify_url: { type: string, format: uri, pattern: "^https://" }
        redirect_url: { type: string, format: uri, pattern: "^https://" }
        name: { type: string, maxLength: 500 }
        signature: { type: string, pattern: "^[0-9a-f]{32}$" }
      example:
        pid: "100000000001"
        order_id: invoice-1001
        currency: USD
        amount: "12.50"
        notify_url: https://merchant.example/notify
        signature: 0123456789abcdef0123456789abcdef
    GmpayCreateData:
      type: object
      required: [trade_id, order_id, amount, currency, actual_amount, receive_address, token, status, expiration_time, payment_url]
      properties:
        trade_id: { type: string, format: uuid }
        order_id: { type: string }
        amount: { type: string }
        currency: { type: string }
        actual_amount: { type: string }
        receive_address: { type: string }
        token: { type: string }
        status: { $ref: "#/components/schemas/OrderStatus" }
        expiration_time: { type: integer }
        payment_url: { type: string, format: uri }
    GmpayCreateResponse:
      allOf:
        - { $ref: "#/components/schemas/GatewayEnvelope" }
        - type: object
          properties:
            data: { $ref: "#/components/schemas/GmpayCreateData" }
    GmpayNotification:
      type: object
      required: [pid, trade_id, order_id, amount, actual_amount, receive_address, token, block_transaction_id, status, signature]
      properties:
        pid: { type: string }
        trade_id: { type: string, format: uuid }
        order_id: { type: string }
        amount: { type: string }
        actual_amount: { type: string }
        receive_address: { type: string }
        token: { type: string }
        block_transaction_id: { type: string }
        status: { $ref: "#/components/schemas/OrderStatus" }
        signature: { type: string, pattern: "^[0-9a-f]{32}$" }
      example:
        pid: "100000000001"
        trade_id: 73e3648b-b257-47e6-a510-12772cac0448
        order_id: invoice-1001
        amount: "12.50"
        actual_amount: "12.50"
        receive_address: TExampleAddress
        token: USDT
        block_transaction_id: transaction-hash
        status: paid
        signature: 0123456789abcdef0123456789abcdef
    EpayCreateRequest:
      type: object
      required: [pid, money, out_trade_no, notify_url, sign]
      properties:
        pid: { type: string }
        money: { type: string }
        out_trade_no: { type: string, maxLength: 128 }
        notify_url: { type: string, format: uri }
        return_url: { type: string, format: uri }
        name: { type: string, maxLength: 500 }
        type: { type: string, description: alipay or asset.network }
        sign: { type: string, pattern: "^[0-9a-f]{32}$" }
        sign_type: { const: MD5 }
    GatewayEnvelope:
      type: object
      required: [status_code, message, data, request_id]
      properties:
        status_code: { type: integer }
        message: { type: string }
        data: {}
        request_id: { type: string }
      example:
        status_code: 10009
        message: invalid parameters
        data: null
        request_id: 73e3648b-b257-47e6-a510-12772cac0448
