{
  "openapi": "3.0.3",
  "info": {
    "title": "Gentleman Pay 商户支付 API",
    "version": "0.1.2",
    "description": "平台商户接口。TEST 联调根地址为 https://sandbox-api.gentleman-pay.com，站点和凭据由平台单独开通。HMAC 签名必须由服务端生成；仅填写 API Key 不足以调用。正式环境另行开通。"
  },
  "servers": [
    {
      "url": "https://sandbox-api.gentleman-pay.com",
      "description": "TEST 沙箱 API；使用已开通的 TEST 凭据，正式环境另行提供"
    }
  ],
  "security": [
    {
      "MerchantApiKey": []
    }
  ],
  "paths": {
    "/v1/payment-orders": {
      "post": {
        "summary": "创建支付订单",
        "operationId": "createOrder",
        "description": "权限 payments:create。持久保存原幂等键与请求；重放可返回原始快照，当前付款状态应查单。",
        "tags": [
          "订单"
        ],
        "security": [
          {
            "MerchantApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "X-Pay-Signature-Version",
            "in": "header",
            "required": true,
            "description": "固定 v1",
            "schema": {
              "type": "string",
              "enum": [
                "v1"
              ]
            }
          },
          {
            "name": "X-Pay-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix 秒级时间戳",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Nonce",
            "in": "header",
            "required": true,
            "description": "每次请求生成新的随机 nonce",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Signature",
            "in": "header",
            "required": true,
            "description": "HMAC-SHA256，无填充 base64url；生成规则见签名章节",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "写请求幂等键；重试保持原键与原始正文",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "201": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "description": "请求参数无效"
          },
          "401": {
            "description": "签名或身份校验失败"
          },
          "403": {
            "description": "权限不足"
          },
          "404": {
            "description": "资源不存在或不可访问"
          },
          "409": {
            "description": "幂等冲突或当前状态不允许"
          },
          "429": {
            "description": "请求频率受限"
          },
          "503": {
            "description": "暂不可用"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateOrder"
              },
              "example": {
                "merchantOrderNo": "shop-order-20261114-001",
                "siteId": "11111111-1111-4111-8111-111111111111",
                "amountMinor": 1000,
                "currency": "GBP",
                "returnUrl": "https://merchant.example/payment/return",
                "cancelUrl": "https://merchant.example/payment/cancel",
                "customer": {
                  "name": "Test Buyer",
                  "email": "buyer@example.com"
                },
                "shipping": {
                  "country": "GB",
                  "region": null,
                  "city": "London",
                  "postalCode": "SW1A 1AA",
                  "line1": "1 Example Street",
                  "line2": null
                },
                "items": [
                  {
                    "externalProductId": "SKU-DEMO-001",
                    "name": "Test product",
                    "quantity": 2,
                    "unitPriceMinor": 500
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/v1/payment-orders/{id}": {
      "get": {
        "summary": "查询支付订单",
        "operationId": "getOrder",
        "description": "权限 payments:read。GET 正文和签名幂等行为空；核对平台订单、站点、商户单号、金额、币种及 PAID。",
        "tags": [
          "订单"
        ],
        "security": [
          {
            "MerchantApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "X-Pay-Signature-Version",
            "in": "header",
            "required": true,
            "description": "固定 v1",
            "schema": {
              "type": "string",
              "enum": [
                "v1"
              ]
            }
          },
          {
            "name": "X-Pay-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix 秒级时间戳",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Nonce",
            "in": "header",
            "required": true,
            "description": "每次请求生成新的随机 nonce",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Signature",
            "in": "header",
            "required": true,
            "description": "HMAC-SHA256，无填充 base64url；生成规则见签名章节",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "完整资源 UUID"
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          },
          "400": {
            "description": "请求参数无效"
          },
          "401": {
            "description": "签名或身份校验失败"
          },
          "403": {
            "description": "权限不足"
          },
          "404": {
            "description": "资源不存在或不可访问"
          },
          "409": {
            "description": "幂等冲突或当前状态不允许"
          },
          "429": {
            "description": "请求频率受限"
          },
          "503": {
            "description": "暂不可用"
          }
        }
      }
    },
    "/v1/checkout-sessions": {
      "post": {
        "summary": "创建收银台会话",
        "operationId": "createCheckout",
        "description": "权限 payments:create。读取首次 Location，由用户浏览器访问；服务端不要跟随重定向。 当前 TEST 收银台来源为 https://test-pay.gentleman-pay.com:8443；按首次响应 Location 跳转，API 与收银台来源分别配置。",
        "tags": [
          "收银台"
        ],
        "security": [
          {
            "MerchantApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "X-Pay-Signature-Version",
            "in": "header",
            "required": true,
            "description": "固定 v1",
            "schema": {
              "type": "string",
              "enum": [
                "v1"
              ]
            }
          },
          {
            "name": "X-Pay-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix 秒级时间戳",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Nonce",
            "in": "header",
            "required": true,
            "description": "每次请求生成新的随机 nonce",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Signature",
            "in": "header",
            "required": true,
            "description": "HMAC-SHA256，无填充 base64url；生成规则见签名章节",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "写请求幂等键；重试保持原键与原始正文",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "201": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Checkout"
                }
              }
            },
            "headers": {
              "Location": {
                "description": "仅首次创建返回一次性浏览器访问地址，幂等重放不重新发放。",
                "schema": {
                  "type": "string",
                  "format": "uri"
                }
              }
            }
          },
          "400": {
            "description": "请求参数无效"
          },
          "401": {
            "description": "签名或身份校验失败"
          },
          "403": {
            "description": "权限不足"
          },
          "404": {
            "description": "资源不存在或不可访问"
          },
          "409": {
            "description": "幂等冲突或当前状态不允许"
          },
          "429": {
            "description": "请求频率受限"
          },
          "503": {
            "description": "暂不可用"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCheckout"
              },
              "example": {
                "orderId": "22222222-2222-4222-8222-222222222222",
                "ttlSeconds": 1800
              }
            }
          }
        }
      }
    },
    "/v1/checkout-sessions/{id}": {
      "get": {
        "summary": "查询收银台会话",
        "operationId": "getCheckout",
        "description": "权限 payments:read；使用创建该会话的同一凭据。",
        "tags": [
          "收银台"
        ],
        "security": [
          {
            "MerchantApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "X-Pay-Signature-Version",
            "in": "header",
            "required": true,
            "description": "固定 v1",
            "schema": {
              "type": "string",
              "enum": [
                "v1"
              ]
            }
          },
          {
            "name": "X-Pay-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix 秒级时间戳",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Nonce",
            "in": "header",
            "required": true,
            "description": "每次请求生成新的随机 nonce",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Signature",
            "in": "header",
            "required": true,
            "description": "HMAC-SHA256，无填充 base64url；生成规则见签名章节",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "完整资源 UUID"
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Checkout"
                }
              }
            }
          },
          "400": {
            "description": "请求参数无效"
          },
          "401": {
            "description": "签名或身份校验失败"
          },
          "403": {
            "description": "权限不足"
          },
          "404": {
            "description": "资源不存在或不可访问"
          },
          "409": {
            "description": "幂等冲突或当前状态不允许"
          },
          "429": {
            "description": "请求频率受限"
          },
          "503": {
            "description": "暂不可用"
          }
        }
      }
    },
    "/v1/checkout-sessions/{id}/cancel": {
      "post": {
        "summary": "取消收银台会话",
        "operationId": "cancelCheckout",
        "description": "权限 payments:create；使用创建该会话的同一凭据，正文为 {}。取消会话不等于退款。",
        "tags": [
          "收银台"
        ],
        "security": [
          {
            "MerchantApiKey": []
          }
        ],
        "parameters": [
          {
            "name": "X-Pay-Signature-Version",
            "in": "header",
            "required": true,
            "description": "固定 v1",
            "schema": {
              "type": "string",
              "enum": [
                "v1"
              ]
            }
          },
          {
            "name": "X-Pay-Timestamp",
            "in": "header",
            "required": true,
            "description": "Unix 秒级时间戳",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Nonce",
            "in": "header",
            "required": true,
            "description": "每次请求生成新的随机 nonce",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Pay-Signature",
            "in": "header",
            "required": true,
            "description": "HMAC-SHA256，无填充 base64url；生成规则见签名章节",
            "schema": {
              "type": "string",
              "pattern": "^[A-Za-z0-9_-]{43}$"
            }
          },
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "完整资源 UUID"
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": true,
            "description": "写请求幂等键；重试保持原键与原始正文",
            "schema": {
              "type": "string",
              "minLength": 1,
              "maxLength": 128
            }
          }
        ],
        "responses": {
          "200": {
            "description": "成功",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Checkout"
                }
              }
            }
          },
          "400": {
            "description": "请求参数无效"
          },
          "401": {
            "description": "签名或身份校验失败"
          },
          "403": {
            "description": "权限不足"
          },
          "404": {
            "description": "资源不存在或不可访问"
          },
          "409": {
            "description": "幂等冲突或当前状态不允许"
          },
          "429": {
            "description": "请求频率受限"
          },
          "503": {
            "description": "暂不可用"
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Empty"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "MerchantApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Pay-Api-Key",
        "description": "还须发送动态 HMAC 签名、时间戳和 nonce；Secret 不发送。"
      }
    },
    "schemas": {
      "Customer": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "email": {
            "type": "string",
            "minLength": 1,
            "maxLength": 254,
            "format": "email"
          }
        },
        "required": [
          "name",
          "email"
        ]
      },
      "Shipping": {
        "type": "object",
        "properties": {
          "country": {
            "type": "string",
            "pattern": "^[A-Z]{2}$"
          },
          "region": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "nullable": true
          },
          "city": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "postalCode": {
            "type": "string",
            "minLength": 1,
            "maxLength": 30
          },
          "line1": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "line2": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "nullable": true
          }
        },
        "required": [
          "country",
          "city",
          "postalCode",
          "line1"
        ]
      },
      "Item": {
        "type": "object",
        "properties": {
          "externalProductId": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200
          },
          "quantity": {
            "type": "integer",
            "format": "int32",
            "minimum": 1,
            "maximum": 10000
          },
          "unitPriceMinor": {
            "type": "integer",
            "format": "int64",
            "minimum": 1
          }
        },
        "required": [
          "externalProductId",
          "name",
          "quantity",
          "unitPriceMinor"
        ]
      },
      "CreateOrder": {
        "type": "object",
        "properties": {
          "merchantOrderNo": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100,
            "description": "商户订单号；同一环境与合作商范围内唯一。"
          },
          "siteId": {
            "type": "string",
            "format": "uuid"
          },
          "amountMinor": {
            "type": "integer",
            "format": "int64",
            "minimum": 1,
            "description": "最小货币单位整数，必须等于商品明细金额之和。"
          },
          "currency": {
            "type": "string",
            "pattern": "^[A-Z]{3}$",
            "description": "必须为当前合作商获准币种。"
          },
          "returnUrl": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048,
            "format": "uri"
          },
          "cancelUrl": {
            "type": "string",
            "minLength": 1,
            "maxLength": 2048,
            "format": "uri"
          },
          "customer": {
            "$ref": "#/components/schemas/Customer"
          },
          "shipping": {
            "$ref": "#/components/schemas/Shipping"
          },
          "items": {
            "type": "array",
            "minItems": 1,
            "maxItems": 100,
            "items": {
              "$ref": "#/components/schemas/Item"
            }
          }
        },
        "required": [
          "merchantOrderNo",
          "siteId",
          "amountMinor",
          "currency",
          "returnUrl",
          "cancelUrl",
          "customer",
          "shipping",
          "items"
        ]
      },
      "Order": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "merchantOrderNo": {
            "type": "string"
          },
          "siteId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "description": "例如 UNPAID、PAID。付款确认只接受匹配原订单的 PAID。"
          },
          "amountMinor": {
            "type": "integer",
            "format": "int64",
            "minimum": 1
          },
          "currency": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          }
        },
        "required": [
          "id",
          "merchantOrderNo",
          "siteId",
          "status",
          "amountMinor",
          "currency",
          "createdAt"
        ]
      },
      "CreateCheckout": {
        "type": "object",
        "properties": {
          "orderId": {
            "type": "string",
            "format": "uuid"
          },
          "ttlSeconds": {
            "type": "integer",
            "minimum": 300,
            "maximum": 3600,
            "default": 1800,
            "nullable": true
          }
        },
        "required": [
          "orderId"
        ]
      },
      "Checkout": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "orderId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "OPEN",
              "COMPLETED",
              "EXPIRED",
              "CANCELLED"
            ]
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "checkoutUrl": {
            "type": "string",
            "format": "uri",
            "description": "无首次访问令牌；首次跳转须使用创建响应 Location。"
          }
        },
        "required": [
          "id",
          "orderId",
          "status",
          "expiresAt",
          "checkoutUrl"
        ]
      },
      "Empty": {
        "type": "object",
        "additionalProperties": false
      },
      "PaidNotification": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "type": {
            "type": "string",
            "enum": [
              "payment_order.paid"
            ]
          },
          "environment": {
            "type": "string",
            "enum": [
              "TEST",
              "PRODUCTION"
            ]
          },
          "orderId": {
            "type": "string",
            "format": "uuid"
          },
          "siteId": {
            "type": "string",
            "format": "uuid"
          },
          "merchantOrderNo": {
            "type": "string"
          },
          "amountMinor": {
            "type": "integer",
            "format": "int64",
            "minimum": 1
          },
          "currency": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "PAID"
            ]
          }
        },
        "required": [
          "id",
          "type",
          "environment",
          "orderId",
          "siteId",
          "merchantOrderNo",
          "amountMinor",
          "currency",
          "status"
        ]
      }
    }
  }
}
