{
  "openapi": "3.1.0",
  "info": {
    "title": "SupraPay merchant API",
    "version": "1",
    "description": "Crypto payment gateway, merchant side.\n\n**Signing.** Every request carries X-Gw-Key (key id), X-Gw-Ts (unix seconds, ±5 min), X-Gw-Nonce (16–64 printable ASCII, unique per request) and X-Gw-Sign: base64 Ed25519 over `ts \\n nonce \\n METHOD \\n path \\n query \\n hex(sha256(body))`. An unsigned or badly signed request is 401 on any path, including ones that do not exist.\n\n**Amounts** are decimal strings in whole units of the asset (\"12.5\"), never numbers.\n\n**Errors** are `{\"error\": {\"code\", \"message\"}}`. Besides the codes listed per operation, any request can get 401 unauthenticated / replay, 403 ip_not_allowed / merchant_suspended, 413 body_too_large (over 64 KiB), 429 rate_limited and 500 internal.\n\n**Callbacks** are listed under webhooks: POST to the URL set for the merchant, signed with X-Gw-Sign = hex(HMAC-SHA256(secret bytes, X-Gw-Ts + \"\\n\" + raw body)). Treat a callback as a reason to ask the API, never as proof of payment."
  },
  "servers": [
    {
      "url": "https://pay.suprapay.org"
    }
  ],
  "security": [
    {
      "GwSignature": []
    }
  ],
  "components": {
    "securitySchemes": {
      "GwSignature": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Gw-Sign",
        "description": "Ed25519 signature (base64) over\nts \"\\n\" nonce \"\\n\" METHOD \"\\n\" path \"\\n\" query \"\\n\" hex(sha256(body)).\nAlso send X-Gw-Key (key id), X-Gw-Ts (unix seconds, ±5 min) and\nX-Gw-Nonce (16–64 printable ASCII, unique per request).\n"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "example": "amount_out_of_range"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "Payment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "txid": {
            "type": "string"
          },
          "asset": {
            "type": "string",
            "example": "USDT-TRC20"
          },
          "amount": {
            "type": "string",
            "example": "25"
          },
          "from": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "seen",
              "confirmed",
              "credited",
              "orphaned",
              "dust",
              "unmatched"
            ]
          },
          "seen_at": {
            "type": "string",
            "format": "date-time"
          },
          "confirmed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "Invoice": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "order_id": {
            "type": "string"
          },
          "asset": {
            "type": "string",
            "example": "USDT-TRC20"
          },
          "chain": {
            "type": "string",
            "example": "tron"
          },
          "amount": {
            "type": "string",
            "example": "25",
            "description": "What the payer is asked for, markup included"
          },
          "paid_amount": {
            "type": "string",
            "example": "0"
          },
          "surcharge": {
            "type": "string",
            "example": "0",
            "description": "The operator's markup included in amount; \"0\" without one"
          },
          "credited": {
            "type": "string",
            "example": "25",
            "description": "What the merchant is credited once paid: amount − surcharge"
          },
          "accuracy_percent": {
            "type": "string",
            "example": "1.5"
          },
          "address": {
            "type": "string"
          },
          "address_display": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "partially_paid",
              "paid",
              "paid_late",
              "expired",
              "cancelled"
            ]
          },
          "customer_ref": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "return_url": {
            "type": "string",
            "format": "uri"
          },
          "pay_url": {
            "type": "string",
            "format": "uri",
            "description": "Hosted payment page"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "paid_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "payments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Payment"
            }
          }
        }
      },
      "Wallet": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "chain": {
            "type": "string",
            "example": "tron"
          },
          "customer_ref": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "address_display": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Asset": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "USDT-TRC20"
          },
          "chain": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "native",
              "token"
            ]
          },
          "contract": {
            "type": "string"
          },
          "decimals": {
            "type": "integer"
          },
          "min_amount": {
            "type": "string"
          },
          "max_amount": {
            "type": "string"
          },
          "display": {
            "type": "string"
          }
        }
      },
      "Offer": {
        "type": "object",
        "description": "What the checkout amount comes to in one coin right now",
        "properties": {
          "asset": {
            "type": "string",
            "example": "BTC"
          },
          "chain": {
            "type": "string",
            "example": "btc"
          },
          "amount": {
            "type": "string",
            "example": "50.02",
            "description": "What the payer would be asked for in this coin right now, operator markup included, rounded up: dollar stablecoins to the cent, other coins to 6 decimals (8 for BTC)"
          },
          "rate": {
            "type": "string",
            "example": "77238.00000000",
            "description": "Fiat per whole coin (median of agreeing sources)"
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "example": [
              "coingecko",
              "kraken",
              "okx"
            ]
          }
        }
      },
      "Checkout": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "order_id": {
            "type": "string"
          },
          "currency": {
            "type": "string",
            "enum": [
              "USD",
              "EUR",
              "RUB"
            ]
          },
          "amount": {
            "type": "string",
            "example": "50.00"
          },
          "assets": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Empty means every enabled asset"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "selected",
              "expired"
            ]
          },
          "pay_url": {
            "type": "string",
            "format": "uri",
            "description": "Hosted page where the payer picks a coin"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "offers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Offer"
            },
            "description": "Only while open"
          },
          "asset": {
            "type": "string",
            "description": "The chosen coin",
            "once selected": null
          },
          "rate": {
            "type": "string",
            "description": "The rate the amount was fixed at"
          },
          "rate_sources": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "invoice": {
            "$ref": "#/components/schemas/Invoice"
          }
        }
      },
      "Balance": {
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "example": "USDT-TRC20"
          },
          "amount": {
            "type": "string",
            "example": "1250.5"
          }
        }
      },
      "PayoutRequest": {
        "type": "object",
        "required": [
          "order_id",
          "asset",
          "address",
          "amount"
        ],
        "properties": {
          "order_id": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_.:@-]{1,64}$"
          },
          "asset": {
            "type": "string",
            "example": "USDT-TRC20"
          },
          "address": {
            "type": "string"
          },
          "amount": {
            "type": "string",
            "example": "100"
          }
        }
      },
      "Payout": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "order_id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "payout",
              "refund"
            ]
          },
          "source": {
            "type": "string",
            "enum": [
              "api",
              "cabinet",
              "operator"
            ],
            "description": "Who asked for it: a signed API request, a request in the merchant dashboard (always approved by the operator), or the operator on the merchant's behalf"
          },
          "payment_id": {
            "type": "string",
            "format": "uuid",
            "description": "For refunds"
          },
          "chain": {
            "type": "string"
          },
          "asset": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "amount": {
            "type": "string"
          },
          "fee": {
            "type": "string",
            "description": "The operator's fee",
            "debited with the amount": null
          },
          "status": {
            "type": "string",
            "enum": [
              "pending_approval",
              "approved",
              "sending",
              "sent",
              "confirmed",
              "failed",
              "rejected",
              "cancelled"
            ]
          },
          "txid": {
            "type": "string"
          },
          "error": {
            "type": "string",
            "description": "Why a payout failed or was rejected"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "sent_at": {
            "type": "string",
            "format": "date-time"
          },
          "closed_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "InvoiceEventData": {
        "type": "object",
        "properties": {
          "invoice_id": {
            "type": "string",
            "format": "uuid"
          },
          "order_id": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "partially_paid",
              "paid",
              "paid_late",
              "expired"
            ]
          },
          "asset": {
            "type": "string",
            "description": "Absent on invoice.expired"
          },
          "amount": {
            "type": "string"
          },
          "paid_amount": {
            "type": "string"
          },
          "accuracy_percent": {
            "type": "string"
          },
          "payment_id": {
            "type": "string",
            "format": "uuid"
          },
          "txid": {
            "type": "string"
          },
          "from": {
            "type": "string"
          },
          "customer_ref": {
            "type": "string"
          },
          "surcharge": {
            "type": "string",
            "description": "The operator's markup in the invoice"
          },
          "fee": {
            "type": "string",
            "description": "Withheld from this payment; the merchant is credited the payment's amount minus fee"
          },
          "checkout_id": {
            "type": "string",
            "format": "uuid",
            "description": "Only for an invoice made from a checkout"
          },
          "fiat": {
            "type": "object",
            "description": "Only for an invoice made from a checkout; for reference — credit by paid_amount",
            "properties": {
              "currency": {
                "type": "string"
              },
              "amount": {
                "type": "string"
              },
              "rate": {
                "type": "string"
              }
            }
          }
        }
      },
      "PaymentReceivedData": {
        "type": "object",
        "properties": {
          "payment_id": {
            "type": "string",
            "format": "uuid"
          },
          "wallet_id": {
            "type": "string",
            "format": "uuid"
          },
          "customer_ref": {
            "type": "string"
          },
          "chain": {
            "type": "string"
          },
          "asset": {
            "type": "string"
          },
          "amount": {
            "type": "string"
          },
          "txid": {
            "type": "string"
          },
          "from": {
            "type": "string"
          },
          "address": {
            "type": "string"
          }
        }
      },
      "PaymentUnmatchedData": {
        "type": "object",
        "properties": {
          "payment_id": {
            "type": "string",
            "format": "uuid"
          },
          "chain": {
            "type": "string"
          },
          "asset": {
            "type": "string"
          },
          "txid": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "reason": {
            "type": "string"
          }
        }
      },
      "PayoutEventData": {
        "type": "object",
        "properties": {
          "payout_id": {
            "type": "string",
            "format": "uuid"
          },
          "order_id": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "payout",
              "refund"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "sent",
              "confirmed",
              "failed",
              "rejected"
            ]
          },
          "chain": {
            "type": "string"
          },
          "asset": {
            "type": "string"
          },
          "address": {
            "type": "string"
          },
          "amount": {
            "type": "string"
          },
          "fee": {
            "type": "string"
          },
          "txid": {
            "type": "string"
          },
          "payment_id": {
            "type": "string",
            "format": "uuid",
            "description": "For refunds"
          },
          "error": {
            "type": "string",
            "description": "Why it failed or was rejected"
          }
        }
      },
      "InvoiceEvent": {
        "type": "object",
        "description": "An invoice changed status",
        "required": [
          "event_id",
          "event",
          "occurred_at",
          "data"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid",
            "description": "Idempotency key: the same event may arrive twice"
          },
          "event": {
            "type": "string",
            "enum": [
              "invoice.partially_paid",
              "invoice.paid",
              "invoice.paid_late",
              "invoice.expired"
            ]
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/InvoiceEventData"
          }
        }
      },
      "PaymentReceivedEvent": {
        "type": "object",
        "description": "A payment to a permanent wallet was credited",
        "required": [
          "event_id",
          "event",
          "occurred_at",
          "data"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid",
            "description": "Idempotency key: the same event may arrive twice"
          },
          "event": {
            "type": "string",
            "enum": [
              "payment.received"
            ]
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/PaymentReceivedData"
          }
        }
      },
      "PaymentUnmatchedEvent": {
        "type": "object",
        "description": "Money arrived that cannot be credited (a cancelled invoice, another asset…); the operator resolves it",
        "required": [
          "event_id",
          "event",
          "occurred_at",
          "data"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid",
            "description": "Idempotency key: the same event may arrive twice"
          },
          "event": {
            "type": "string",
            "enum": [
              "payment.unmatched"
            ]
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/PaymentUnmatchedData"
          }
        }
      },
      "PayoutEvent": {
        "type": "object",
        "description": "A payout or refund changed status",
        "required": [
          "event_id",
          "event",
          "occurred_at",
          "data"
        ],
        "properties": {
          "event_id": {
            "type": "string",
            "format": "uuid",
            "description": "Idempotency key: the same event may arrive twice"
          },
          "event": {
            "type": "string",
            "enum": [
              "payout.sent",
              "payout.confirmed",
              "payout.failed",
              "payout.rejected"
            ]
          },
          "occurred_at": {
            "type": "string",
            "format": "date-time"
          },
          "data": {
            "$ref": "#/components/schemas/PayoutEventData"
          }
        }
      }
    },
    "responses": {
      "Conflict": {
        "description": "See error.code",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "BadRequest": {
        "description": "See error.code",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Unauthenticated": {
        "description": "Missing or invalid signature, stale timestamp, or replayed nonce",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "NotFound": {
        "description": "No such object for this merchant",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    }
  },
  "paths": {
    "/v1/invoices": {
      "post": {
        "summary": "Create an invoice (one address per order)",
        "description": "Idempotent on order_id; the same order_id with a different asset or amount is 409.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "order_id",
                  "asset",
                  "amount"
                ],
                "properties": {
                  "order_id": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_.:@-]{1,64}$"
                  },
                  "asset": {
                    "type": "string",
                    "example": "USDT-TRC20"
                  },
                  "amount": {
                    "type": "string",
                    "example": "25"
                  },
                  "ttl_sec": {
                    "type": "integer",
                    "example": 3600
                  },
                  "customer_ref": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_.:@-]{1,64}$"
                  },
                  "accuracy_percent": {
                    "type": "string",
                    "example": "1.5",
                    "description": "Underpayment tolerance; at most two decimals"
                  },
                  "return_url": {
                    "type": "string",
                    "format": "uri",
                    "description": "https only"
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 200
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created (or the existing invoice for this order_id)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invoice": {
                      "$ref": "#/components/schemas/Invoice"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_request, invalid_amount, invalid_accuracy, asset_disabled, amount_out_of_range, bad_ttl",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "409": {
            "description": "order_mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited or quota_exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "no_address — retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/invoices/{id}": {
      "get": {
        "summary": "Invoice by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invoice": {
                      "$ref": "#/components/schemas/Invoice"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/invoices/by-order/{order_id}": {
      "get": {
        "summary": "Invoice by your order id",
        "parameters": [
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invoice": {
                      "$ref": "#/components/schemas/Invoice"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/invoices/{id}/cancel": {
      "post": {
        "summary": "Cancel an open invoice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled (idempotent)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "invoice": {
                      "$ref": "#/components/schemas/Invoice"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "not_cancellable — money already arrived",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/wallets": {
      "post": {
        "summary": "Permanent address for a customer on a chain (idempotent)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "chain",
                  "customer_ref"
                ],
                "properties": {
                  "chain": {
                    "type": "string",
                    "example": "tron"
                  },
                  "customer_ref": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_.:@-]{1,64}$"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created or existing",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "wallet": {
                      "$ref": "#/components/schemas/Wallet"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "asset_disabled / invalid_request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/wallets/{id}": {
      "get": {
        "summary": "Wallet by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "wallet": {
                      "$ref": "#/components/schemas/Wallet"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/wallets/{id}/payments": {
      "get": {
        "summary": "Credited payments to a wallet, newest first",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "wallet": {
                      "$ref": "#/components/schemas/Wallet"
                    },
                    "payments": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Payment"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/{id}": {
      "get": {
        "summary": "Payment by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payment": {
                      "$ref": "#/components/schemas/Payment"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/assets": {
      "get": {
        "summary": "Enabled assets with limits",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "assets": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Asset"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/rates": {
      "get": {
        "summary": "Price of one whole coin of every enabled asset (only coins with an agreed price)",
        "parameters": [
          {
            "name": "currency",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "USD",
                "EUR",
                "RUB"
              ],
              "default": "USD"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "currency": {
                      "type": "string"
                    },
                    "rates": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "asset": {
                            "type": "string"
                          },
                          "price": {
                            "type": "string"
                          },
                          "sources": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/checkouts": {
      "post": {
        "summary": "Create a checkout priced in fiat; the payer picks the coin",
        "description": "Idempotent on order_id; the same order_id with another currency or amount, or one already used by an invoice, is 409.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "order_id",
                  "currency",
                  "amount"
                ],
                "properties": {
                  "order_id": {
                    "type": "string",
                    "pattern": "^[A-Za-z0-9_.:@-]{1,64}$"
                  },
                  "currency": {
                    "type": "string",
                    "enum": [
                      "USD",
                      "EUR",
                      "RUB"
                    ]
                  },
                  "amount": {
                    "type": "string",
                    "example": "50.00",
                    "description": "At most two decimals"
                  },
                  "assets": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 32
                  },
                  "ttl_sec": {
                    "type": "integer",
                    "minimum": 300,
                    "maximum": 604800,
                    "default": 1800
                  },
                  "customer_ref": {
                    "type": "string"
                  },
                  "accuracy_percent": {
                    "type": "string"
                  },
                  "return_url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "description": {
                    "type": "string",
                    "maxLength": 200
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "checkout": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "The existing checkout for this order_id",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "checkout": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      }
    },
    "/v1/checkouts/{id}": {
      "get": {
        "summary": "Checkout by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "checkout": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/checkouts/by-order/{order_id}": {
      "get": {
        "summary": "Checkout by your order id",
        "parameters": [
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "checkout": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/checkouts/{id}/select": {
      "post": {
        "summary": "Choose the coin on the payer's behalf; fixes the amount at the current rate and creates the invoice",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "asset"
                ],
                "properties": {
                  "asset": {
                    "type": "string",
                    "example": "BTC"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Selected (the same coin again returns the same invoice)",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "checkout": {
                      "$ref": "#/components/schemas/Checkout"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "not_offered (no agreed price or not in the list), already_selected (another coin), checkout_closed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "no_address — retry shortly",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/balance": {
      "get": {
        "summary": "The merchant's balance per asset",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "balances": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Balance"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/payouts": {
      "post": {
        "summary": "Send from the balance to an address",
        "description": "Idempotent on order_id. Debits amount + fee at once. Above the operator's approval threshold the payout waits in\npending_approval. The signed request is stored and re-verified by the signing service before the transaction is made.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payout": {
                      "$ref": "#/components/schemas/Payout"
                    }
                  }
                }
              }
            }
          },
          "200": {
            "description": "The existing payout for this order_id",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payout": {
                      "$ref": "#/components/schemas/Payout"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "invalid_address, invalid_amount, asset_disabled, payout_not_allowed, over_limit",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "payouts_disabled",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "insufficient_balance, order_mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "Recent payouts, newest first",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payouts": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Payout"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/payouts/batch": {
      "post": {
        "summary": "Up to 100 payouts in one signed request; each succeeds or fails on its own",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "payouts"
                ],
                "properties": {
                  "payouts": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "$ref": "#/components/schemas/PayoutRequest"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "One result per item, in order",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "order_id": {
                            "type": "string"
                          },
                          "payout": {
                            "$ref": "#/components/schemas/Payout"
                          },
                          "error": {
                            "type": "object",
                            "properties": {
                              "code": {
                                "type": "string"
                              },
                              "message": {
                                "type": "string"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/payouts/{id}": {
      "get": {
        "summary": "Payout by id",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payout": {
                      "$ref": "#/components/schemas/Payout"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/payouts/by-order/{order_id}": {
      "get": {
        "summary": "Payout by your order id",
        "parameters": [
          {
            "name": "order_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payout": {
                      "$ref": "#/components/schemas/Payout"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/v1/payouts/{id}/cancel": {
      "post": {
        "summary": "Cancel a payout still waiting for approval; the balance is restored",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Cancelled",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payout": {
                      "$ref": "#/components/schemas/Payout"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "not_cancellable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/payments/{id}/refund": {
      "post": {
        "summary": "Refund a credited payment, in its asset, from the balance",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "order_id",
                  "address",
                  "amount"
                ],
                "properties": {
                  "order_id": {
                    "type": "string"
                  },
                  "address": {
                    "type": "string"
                  },
                  "amount": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "payout": {
                      "$ref": "#/components/schemas/Payout"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "refund_exceeds, insufficient_balance, order_mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "invoice": {
      "post": {
        "summary": "Invoice status changed",
        "description": "Answer 2xx within 10 s, then ask the API for the object's status. Non-2xx is retried with a growing delay (10 s → 6 h) for 7 days.",
        "parameters": [
          {
            "name": "X-Gw-Ts",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Unix seconds; refuse if more than 5 minutes off"
          },
          {
            "name": "X-Gw-Sign",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "hex(HMAC-SHA256(key, X-Gw-Ts + \"\\n\" + raw body)); key = the 64-hex callback secret decoded to 32 bytes"
          },
          {
            "name": "X-Gw-Event",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Gw-Event-Id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvoiceEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          }
        },
        "security": []
      }
    },
    "paymentReceived": {
      "post": {
        "summary": "Payment to a permanent wallet credited",
        "description": "Answer 2xx within 10 s, then ask the API for the object's status. Non-2xx is retried with a growing delay (10 s → 6 h) for 7 days.",
        "parameters": [
          {
            "name": "X-Gw-Ts",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Unix seconds; refuse if more than 5 minutes off"
          },
          {
            "name": "X-Gw-Sign",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "hex(HMAC-SHA256(key, X-Gw-Ts + \"\\n\" + raw body)); key = the 64-hex callback secret decoded to 32 bytes"
          },
          {
            "name": "X-Gw-Event",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Gw-Event-Id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentReceivedEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          }
        },
        "security": []
      }
    },
    "paymentUnmatched": {
      "post": {
        "summary": "Payment that cannot be credited",
        "description": "Answer 2xx within 10 s, then ask the API for the object's status. Non-2xx is retried with a growing delay (10 s → 6 h) for 7 days.",
        "parameters": [
          {
            "name": "X-Gw-Ts",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Unix seconds; refuse if more than 5 minutes off"
          },
          {
            "name": "X-Gw-Sign",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "hex(HMAC-SHA256(key, X-Gw-Ts + \"\\n\" + raw body)); key = the 64-hex callback secret decoded to 32 bytes"
          },
          {
            "name": "X-Gw-Event",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Gw-Event-Id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PaymentUnmatchedEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          }
        },
        "security": []
      }
    },
    "payout": {
      "post": {
        "summary": "Payout or refund status changed",
        "description": "Answer 2xx within 10 s, then ask the API for the object's status. Non-2xx is retried with a growing delay (10 s → 6 h) for 7 days.",
        "parameters": [
          {
            "name": "X-Gw-Ts",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Unix seconds; refuse if more than 5 minutes off"
          },
          {
            "name": "X-Gw-Sign",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "hex(HMAC-SHA256(key, X-Gw-Ts + \"\\n\" + raw body)); key = the 64-hex callback secret decoded to 32 bytes"
          },
          {
            "name": "X-Gw-Event",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Gw-Event-Id",
            "in": "header",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Accepted"
          }
        },
        "security": []
      }
    }
  }
}
