openapi: 3.0.3
info:
  title: JPYC Pay API
  version: 0.2.0
  description: |
    JPYC の任意金額ガスレス決済 (x402 / EIP-3009) を提供する決済 API。

    ## 決済フロー (x402 2-shot)

    1. merchant サーバ: `POST /v1/charges` (secret key 認証) で charge を作成
    2. 顧客ブラウザ / エージェント: `POST /v1/charges/{id}/pay` を署名なしで叩く
       → `402 Payment Required` + `PAYMENT-REQUIRED` ヘッダ
       (base64url JSON の PaymentRequired。amount / payTo / chain / asset を含む)
    3. クライアントは JPYC 残高を確認し、EIP-712 `TransferWithAuthorization`
       に署名 (nonce は 32 byte ランダムをクライアントが生成)
    4. `POST /v1/charges/{id}/pay` を `PAYMENT-SIGNATURE` ヘッダ
       (base64url JSON の PaymentPayload) 付きで再送
       → 運営 facilitator が on-chain settle → `200 OK` + `PAYMENT-RESPONSE` ヘッダ
    5. merchant サーバへ署名付き webhook `charge.succeeded` が届く

    ## エラー形式

    すべてのエラーは `{ "ok": false, "error": { "code": "...", "message": "..." } }`。

    ## 結果不明 (`settlement_state_unknown`)

    facilitator との通信断などで settle の結果が確定できない場合、502 で
    `settlement_state_unknown` を返す。**このとき再署名・再購入をしてはいけない。**
    リコンサイラが on-chain 照合で自動確定するので、`GET /v1/charges/{id}/status`
    をポーリングして最終状態を確認すること。

    Hosted checkout: 作成結果の checkout_url に購入者を案内できます。
    加盟店が accepted_chain_ids を選択し、決済ごとの available_chain_ids で絞り込めます。
    秘密キーの live/test とDB上の livemode は分離されます。test は送金なしのシミュレーターです。
    本番の成功決済は別途月次で利用料を請求します。返金に応じて手数料を調整します。
servers:
  - url: https://pay.jpyc-service.com
    description: production
  - url: https://stg-pay.jpyc-service.com
    description: staging
tags:
  - name: charges
    description: charge の作成・取得 (secret key 認証)
  - name: payment
    description: x402 決済実行 (公開 — charge id がアクセストークン)
security: []
paths:
  /v1/charges:
    post:
      tags:
        - charges
      summary: charge を作成
      security:
        - secretKey: []
      parameters:
        - name: Idempotency-Key
          in: header
          required: false
          schema:
            type: string
            maxLength: 255
          description: |
            同一キーの再送は既存 charge を 200 で返す (body が異なる場合は
            409 idempotency_conflict)。ネットワーク再送に備え指定を推奨。
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount_jpyc
              properties:
                amount_jpyc:
                  type: string
                  pattern: ^\d+(\.\d{1,18})?$
                  example: "3000"
                  description: 文字列必須。整数 or 小数 (18 桁まで)。最小値は PAY_MIN_CHARGE_JPYC (default 1)
                chain_id:
                  type: integer
                  example: 137
                  description: 省略時 merchant.default_chain_id
                pay_to:
                  type: string
                  description: 加盟店の登録済み受取先と同じアドレスのみ。省略時は登録済み受取先。
                description:
                  type: string
                  maxLength: 500
                metadata:
                  type: object
                  description: merchant の自由領域 (4KB 上限)
                expires_in_seconds:
                  type: integer
                  minimum: 60
                  maximum: 86400
                  default: 3600
                available_chain_ids:
                  type: array
                  items:
                    type: integer
                  minItems: 1
                  maxItems: 12
                  description: 加盟店が許可するチェーンの部分集合。省略時は加盟店の全受付チェーン。
                return_url:
                  type: string
                  format: uri
                  maxLength: 2048
                  description: 設定済みHTTPS origin の戻り先。画面遷移だけで支払済みと判断しないこと。
                cancel_url:
                  type: string
                  format: uri
                  maxLength: 2048
      responses:
        "200":
          description: Idempotency-Key 再送 (既存 charge)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChargeResponse"
        "201":
          description: 作成成功
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChargeResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "409":
          description: idempotency_conflict
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    get:
      tags:
        - charges
      summary: charge 一覧 (カーソルページネーション)
      security:
        - secretKey: []
      parameters:
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
        - name: starting_after
          in: query
          schema:
            type: string
          description: この charge id より古いものを返す
        - name: status
          in: query
          schema:
            type: string
            enum:
              - requires_payment
              - processing
              - succeeded
              - failed
              - expired
      responses:
        "200":
          description: 一覧
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  data:
                    type: object
                    properties:
                      charges:
                        type: array
                        items:
                          $ref: "#/components/schemas/Charge"
                      has_more:
                        type: boolean
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/charges/{id}:
    get:
      tags:
        - charges
      summary: charge 取得 (全フィールド)
      security:
        - secretKey: []
      parameters:
        - $ref: "#/components/parameters/ChargeId"
      responses:
        "200":
          description: charge
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ChargeResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/charges/{id}/pay:
    post:
      tags:
        - payment
      summary: x402 2-shot 決済実行 (公開)
      description: |
        1st shot (PAYMENT-SIGNATURE なし) は 402 + `PAYMENT-REQUIRED` ヘッダを返す。
        2nd shot (PAYMENT-SIGNATURE あり) は facilitator 経由で settle し、
        200 + `PAYMENT-RESPONSE` ヘッダを返す。

        決済済み charge への再送は同じ結果を 200 で返す (冪等リプレイ)。
        レート制限: IP ごとに 30 req/min。
      parameters:
        - $ref: "#/components/parameters/ChargeId"
        - name: PAYMENT-SIGNATURE
          in: header
          required: false
          schema:
            type: string
          description: base64url(JSON PaymentPayload)。2nd shot でのみ付ける
      responses:
        "200":
          description: 2nd shot — settle 成功 (冪等リプレイ含む)
          headers:
            PAYMENT-RESPONSE:
              schema:
                type: string
              description: base64url(JSON SettlementResponse)
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      charge_id:
                        type: string
                      status:
                        type: string
                        example: succeeded
                      tx_hash:
                        type: string
                      network:
                        type: string
                        example: eip155:137
                      payer:
                        type: string
                      amount_atomic:
                        type: string
                      already_settled:
                        type: boolean
                      charge:
                        $ref: "#/components/schemas/Charge"
        "400":
          description: invalid_payment_payload / payload_mismatch / verification_failed
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "402":
          description: >-
            1st shot の支払い要求。照合によって失敗が確定した決済は402で ErrorResponse。送信後の結果不明は502 settlement_state_unknownで返す。確認中の409 charge_processingも含め、再署名せずstatusを照会する。
            testモードはこのエンドポイントから送金できません。
          headers:
            PAYMENT-REQUIRED:
              schema:
                type: string
              description: base64url(JSON PaymentRequired)
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                    example: false
                  error:
                    type: object
                    properties:
                      code:
                        type: string
                        example: payment_required
                      message:
                        type: string
                  data:
                    type: object
                    properties:
                      charge_id:
                        type: string
                      expires_at_unix_ms:
                        type: integer
                      summary:
                        type: object
                        properties:
                          amount_jpyc:
                            type: string
                          amount_atomic:
                            type: string
                          chain_id:
                            type: integer
                          pay_to:
                            type: string
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: charge_already_paid / charge_processing / charge_failed / duplicate_authorization
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "410":
          description: charge_expired
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: rate_limited
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "502":
          description: |
            settlement_state_unknown / facilitator_unreachable / facilitator_error。
            settlement_state_unknown のときは再署名せず /status をポーリングすること。
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/charges/{id}/status:
    get:
      tags:
        - payment
      summary: charge 状態の公開照会 (限定フィールド)
      parameters:
        - $ref: "#/components/parameters/ChargeId"
      responses:
        "200":
          description: 状態
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                      status:
                        type: string
                        enum:
                          - requires_payment
                          - processing
                          - succeeded
                          - failed
                          - expired
                      amount_jpyc:
                        type: string
                      amount_atomic:
                        type: string
                      chain_id:
                        type: integer
                      expires_at_unix_ms:
                        type: integer
                      tx_hash:
                        type: string
                        nullable: true
                      recovered:
                        type: boolean
                      livemode:
                        type: boolean
                      available_chain_ids:
                        type: array
                        items:
                          type: integer
                        minItems: 1
                        maxItems: 12
                      failure_code:
                        type: string
                        nullable: true
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/merchant:
    get:
      summary: 接続先加盟店とキーのモードを取得
      security:
        - secretKey: []
      parameters: []
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/Merchant"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/webhook-endpoints:
    post:
      summary: モード別のHTTPS通知先を登録（同じURLは再利用）
      security:
        - secretKey: []
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
              properties:
                url:
                  type: string
                  format: uri
                  maxLength: 2048
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/WebhookEndpoint"
        "201":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/WebhookEndpoint"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/refunds:
    get:
      summary: 加盟店・モード別の返金を直近100件取得
      security:
        - secretKey: []
      parameters: []
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    type: object
                    properties:
                      refunds:
                        type: array
                        items:
                          $ref: "#/components/schemas/Refund"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      summary: 全額・一部返金を作成。元受取人の署名後に送金
      security:
        - secretKey: []
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
            minLength: 1
            maxLength: 255
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - charge_id
                - amount_jpyc
              properties:
                charge_id:
                  type: string
                amount_jpyc:
                  type: string
                  pattern: ^\d+(\.\d{1,18})?$
                  maxLength: 40
                reason:
                  type: string
                  maxLength: 500
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/Refund"
        "201":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/Refund"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/refunds/{id}:
    get:
      summary: 返金の詳細を取得
      security:
        - secretKey: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/Refund"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/charges/{id}/chain:
    post:
      summary: 未払いの決済のチェーンを変更
      security: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - chain_id
              properties:
                chain_id:
                  type: integer
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/ChargePublicStatus"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/charges/{id}/simulate:
    post:
      summary: テスト専用。送金せずに結果を再現
      security: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcome
              properties:
                outcome:
                  type: string
                  enum:
                    - succeeded
                    - failed
                    - processing
                payer:
                  type: string
                  pattern: ^0x[0-9a-fA-F]{40}$
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/ChargePublicStatus"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /v1/charges/{id}/cancel:
    post:
      summary: 未払いの通常決済をキャンセル
      security: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      responses:
        "200":
          description: 成功
          content:
            application/json:
              schema:
                type: object
                required:
                  - ok
                  - data
                properties:
                  ok:
                    type: boolean
                    enum:
                      - true
                  data:
                    $ref: "#/components/schemas/ChargePublicStatus"
        "400":
          description: 不正な入力
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: 秘密キーが無効または失効済み
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: 存在しないか別加盟店・別モードのデータ
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "409":
          description: 状態・冪等キー・上限の競合
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "413":
          description: 本文は16KBまで
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "429":
          description: レート制限
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
components:
  securitySchemes:
    secretKey:
      type: http
      scheme: bearer
      description: jpyc_sk_live_ または jpyc_sk_test_。サーバーでのみ使用。キーのモードと所有加盟店でデータを分離。
  parameters:
    ChargeId:
      name: id
      in: path
      required: true
      schema:
        type: string
        pattern: ^chg_[0-9a-f]{32}$
  responses:
    BadRequest:
      description: invalid_body / amount_too_small / unsupported_chain
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    Unauthorized:
      description: unauthorized (API キーが無効・失効済み)
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
    NotFound:
      description: charge_not_found
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/ErrorResponse"
  schemas:
    ErrorResponse:
      type: object
      properties:
        ok:
          type: boolean
          example: false
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
    ChargeResponse:
      type: object
      properties:
        ok:
          type: boolean
          example: true
        data:
          $ref: "#/components/schemas/Charge"
    Charge:
      type: object
      properties:
        id:
          type: string
          example: chg_0123456789abcdef0123456789abcdef
        object:
          type: string
          example: charge
        status:
          type: string
          enum:
            - requires_payment
            - processing
            - succeeded
            - failed
            - expired
        amount_jpyc:
          type: string
          example: "3000"
        amount_atomic:
          type: string
          example: "3000000000000000000000"
        chain_id:
          type: integer
          example: 137
        pay_to:
          type: string
        description:
          type: string
          nullable: true
        metadata:
          type: object
        fee_bps:
          type: integer
          example: 100
          description: 記録用スナップショット (v1 では徴収しない)
        fee_amount_atomic:
          type: string
        pay_url:
          type: string
          example: https://pay.jpyc-service.com/v1/charges/chg_…/pay
        expires_at:
          type: string
          format: date-time
        expires_at_unix_ms:
          type: integer
        tx_hash:
          type: string
          nullable: true
        payer:
          type: string
          nullable: true
        recovered:
          type: boolean
          description: リコンサイラの on-chain 照合による復旧で succeeded になった場合 true
        failure_code:
          type: string
          nullable: true
        failure_message:
          type: string
          nullable: true
        settled_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
        livemode:
          type: boolean
        purpose:
          type: string
          enum:
            - payment
            - refund
            - fee
        available_chain_ids:
          type: array
          items:
            type: integer
          minItems: 1
          maxItems: 12
        checkout_url:
          type: string
          format: uri
        return_url:
          type: string
          format: uri
          nullable: true
        cancel_url:
          type: string
          format: uri
          nullable: true
        expected_payer:
          type: string
          nullable: true
      required:
        - livemode
        - purpose
        - available_chain_ids
        - checkout_url
    ChargePublicStatus:
      type: object
      properties:
        id:
          type: string
        status:
          type: string
          enum:
            - requires_payment
            - processing
            - succeeded
            - failed
            - expired
        amount_jpyc:
          type: string
        amount_atomic:
          type: string
        chain_id:
          type: integer
        expires_at_unix_ms:
          type: integer
        tx_hash:
          type: string
          nullable: true
        recovered:
          type: boolean
        livemode:
          type: boolean
        available_chain_ids:
          type: array
          items:
            type: integer
          minItems: 1
          maxItems: 12
        failure_code:
          type: string
          nullable: true
    Refund:
      type: object
      required:
        - id
        - object
        - charge_id
        - transfer_charge_id
        - amount_jpyc
        - amount_atomic
        - status
        - livemode
        - authorization_url
      properties:
        id:
          type: string
        object:
          type: string
          enum:
            - refund
        charge_id:
          type: string
        transfer_charge_id:
          type: string
        amount_jpyc:
          type: string
          pattern: ^\d+(\.\d{1,18})?$
          maxLength: 40
        amount_atomic:
          type: string
        reason:
          type: string
          nullable: true
        livemode:
          type: boolean
        chain_id:
          type: integer
        status:
          type: string
          enum:
            - requires_action
            - processing
            - succeeded
            - failed
        authorization_url:
          type: string
          format: uri
        tx_hash:
          type: string
          nullable: true
        created_at:
          type: string
          format: date-time
    Merchant:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        payout_wallet_address:
          type: string
        default_chain_id:
          type: integer
        accepted_chain_ids:
          type: array
          items:
            type: integer
          minItems: 1
          maxItems: 12
        redirect_origins:
          type: array
          items:
            type: string
            format: uri
        livemode:
          type: boolean
    WebhookEndpoint:
      type: object
      properties:
        id:
          type: string
          format: uuid
        url:
          type: string
          format: uri
        secret:
          type: string
        livemode:
          type: boolean
