{
  "openapi": "3.1.0",
  "info": {
    "title": "Priva-Z public API",
    "version": "1",
    "summary": "Quote, create and follow private crypto swaps; payment requests, Z Pay payments and referral codes.",
    "description": "Priva-Z is a no-account private crypto swap. Every answer is { success: true, data } or { success: false, error } (GET /health and POST /rpc excepted). JSON bodies, at most 10 kB; unknown fields are refused. The full guide for agents, with the rules to follow (the secret note is the user's only receipt: show it, never store it; always a brand-new payout address the user controls; show the quote and get the user's yes before creating a swap), is at https://www.priva-z.app/llms-full.txt.",
    "termsOfService": "https://www.priva-z.app/terms",
    "contact": {
      "name": "Priva-Z support",
      "email": "privaz.app@yahoo.com",
      "url": "https://www.priva-z.app/partners"
    }
  },
  "externalDocs": {
    "description": "Developer guide (plain text)",
    "url": "https://www.priva-z.app/llms-full.txt"
  },
  "servers": [
    {
      "url": "https://privaz-api.vercel.app/api/v1",
      "description": "Public API"
    },
    {
      "url": "http://privaz473ay2g5zuj4hdh6whvdfbxougw3hyl33pgsukbat4wual5qyd.onion/api/v1",
      "description": "The same API on the Tor site"
    }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "health",
        "summary": "Liveness check",
        "description": "Answers { status, timestamp } (not wrapped in success/data).",
        "responses": {
          "200": {
            "description": "Up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status",
                    "timestamp"
                  ],
                  "properties": {
                    "status": {
                      "const": "ok"
                    },
                    "timestamp": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                },
                "example": {
                  "status": "ok",
                  "timestamp": "2026-11-07T12:00:00.000Z"
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/info": {
      "get": {
        "operationId": "getInfo",
        "summary": "Live settings: coins on now, minimums, fee, Fast",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Info"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "cluster": "mainnet-beta",
                    "simulated": false,
                    "feeBps": 50,
                    "minAmount": "0.12",
                    "minAmounts": {
                      "sol": "0.12",
                      "usdc": "0.12",
                      "zec": "0.1"
                    },
                    "routeMinAmounts": {
                      "zec": "0.12",
                      "xmr": "0.62",
                      "xmr-zec": "0.3",
                      "relay": "0.63"
                    },
                    "fast": {
                      "available": true,
                      "minAmount": "0.63"
                    },
                    "sendAssets": [
                      "sol",
                      "btc",
                      "eth",
                      "usdt",
                      "usdc",
                      "ltc"
                    ],
                    "payoutAssets": [
                      "sol",
                      "btc",
                      "eth",
                      "usdt",
                      "usdc",
                      "ltc",
                      "zec",
                      "xmr"
                    ],
                    "assets": {
                      "sol": {
                        "symbol": "SOL",
                        "network": "Solana",
                        "inputDecimals": 2,
                        "max": "9000",
                        "maxStated": false
                      },
                      "zec": {
                        "symbol": "ZEC",
                        "network": "Zcash",
                        "inputDecimals": 8,
                        "maxStated": false
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/swap/quote": {
      "post": {
        "operationId": "quote",
        "summary": "Quote a swap (nothing is created)",
        "description": "Show the user the full quote (estimatedOut, fee, totalCostPct or breakdown, route and expected time) and get their confirmation before creating a swap. Quotes are cached for 30 seconds. Rate limit: 20 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteRequest"
              },
              "example": {
                "amount": "1",
                "route": "zec",
                "sendAsset": "sol",
                "payoutAsset": "sol",
                "includeFast": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Quote"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "amount": "1.000000000",
                    "fee": "0.005000000",
                    "net": "0.995000000",
                    "route": "zec",
                    "feeBps": 50,
                    "simulated": false,
                    "sendAsset": "sol",
                    "payoutAsset": "sol",
                    "minAmount": "0.12",
                    "estimatedOut": "0.9871",
                    "estimatedSolBack": "0.9871",
                    "separateExchanges": false,
                    "routes": [
                      {
                        "route": "zec",
                        "available": true,
                        "minAmount": "0.12",
                        "estimatedOut": "0.9871",
                        "estimatedSolBack": "0.9871",
                        "totalCostPct": 1.3
                      }
                    ],
                    "breakdown": {
                      "feePct": 0.5,
                      "totalPct": 1.3
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/RegionUnavailable"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/swap/challenge": {
      "post": {
        "operationId": "challenge",
        "summary": "A proof-of-work challenge for one new swap",
        "description": "Rate limit: 20 a minute. Solve it locally (see Challenge), then send it with POST /swap/deposit before exp.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "No fields: send {}."
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/Challenge"
                        },
                        {
                          "$ref": "#/components/schemas/NoChallenge"
                        }
                      ]
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "id": "6f1d2c3b-8a4e-4f60-9b1a-2c3d4e5f6a7b",
                    "exp": 1794571200000,
                    "bits": 3,
                    "sig": "0000000000000000000000000000000000000000000000000000000000000000"
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/RegionUnavailable"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/swap/deposit": {
      "post": {
        "operationId": "createDeposit",
        "summary": "Create a swap",
        "description": "Only after the user has confirmed the quote. Answers the secret note (show it to the user first; never store, log or send it elsewhere) and where to pay. On 503, send the very same request again after 1-2 seconds, up to 3 times. Rate limit: 10 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositRequest"
              },
              "example": {
                "amount": "1",
                "returnAddress": "<fresh Solana address of the user>",
                "privacyMode": "standard",
                "route": "zec",
                "challenge": {
                  "id": "6f1d2c3b-8a4e-4f60-9b1a-2c3d4e5f6a7b",
                  "exp": 1794571200000,
                  "bits": 3,
                  "sig": "0000000000000000000000000000000000000000000000000000000000000000"
                },
                "nonce": "11"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Deposit"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "depositId": "6f1d2c3b-8a4e-4f60-9b1a-2c3d4e5f6a7b",
                    "note": "<64 hex characters>",
                    "depositAddress": "<one-time Solana address>",
                    "amount": "1.000000000",
                    "fee": "0.005000000",
                    "net": "0.995000000",
                    "route": "zec",
                    "sendAsset": "sol",
                    "payoutAsset": "sol",
                    "separateExchanges": false,
                    "simulated": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/AddressRefused"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/RegionUnavailable"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/swap/deposit/status": {
      "post": {
        "operationId": "depositStatus",
        "summary": "A swap's progress by its id",
        "description": "Poll every few seconds while waiting for a deposit address, then every 30-60 seconds.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositStatusRequest"
              },
              "example": {
                "depositId": "6f1d2c3b-8a4e-4f60-9b1a-2c3d4e5f6a7b"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/DepositStatus"
                        },
                        {
                          "$ref": "#/components/schemas/ArchivedStatus"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/swap/status": {
      "post": {
        "operationId": "statusByNote",
        "summary": "A swap's progress by its secret note",
        "description": "Also answers refundClaim. Use only when the user hands you the note; never keep it.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NoteRequest"
              },
              "example": {
                "note": "<64 hex characters>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "oneOf": [
                        {
                          "$ref": "#/components/schemas/DepositStatus"
                        },
                        {
                          "$ref": "#/components/schemas/ArchivedStatus"
                        }
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/swap/pay-check": {
      "post": {
        "operationId": "payCheck",
        "summary": "Whether a /pay link is a real, open Priva-Z payment",
        "description": "Answers only { ok }. Rate limit: 60 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayCheckRequest"
              },
              "example": {
                "address": "<Solana deposit address>",
                "lamports": "1000000000"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/PayCheck"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "ok": true
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/swap/refund-challenge": {
      "post": {
        "operationId": "refundChallenge",
        "summary": "A proof-of-work challenge for one refund claim",
        "description": "Always 4 bits; signed for refund claims only. 404 while self-serve refunds are off. Rate limit: 20 a minute.",
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "No fields: send {}."
              },
              "example": {}
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Challenge"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/swap/refund-claim": {
      "post": {
        "operationId": "refundClaim",
        "summary": "Add a refund address to a SOL swap whose SOL waits at its deposit address",
        "description": "When POST /swap/status answers refundClaim available or retry. The refund is sent within a random 30 to 120 minutes. Rate limit: 10 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefundClaimRequest"
              },
              "example": {
                "note": "<64 hex characters>",
                "refundAddress": "<the user's own Solana address>",
                "challenge": {
                  "id": "6f1d2c3b-8a4e-4f60-9b1a-2c3d4e5f6a7b",
                  "exp": 1794571200000,
                  "bits": 4,
                  "sig": "0000000000000000000000000000000000000000000000000000000000000000"
                },
                "nonce": "7"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/RefundClaim"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "claimed": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/AddressRefused"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/swap/quote-for-output": {
      "post": {
        "operationId": "quoteForOutput",
        "summary": "Reverse quote for payment requests: how much to send so that about targetOut arrives",
        "description": "Takes amounts and coins only, never an address. 404 while payment requests are off. Rate limit: 6 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteForOutputRequest"
              },
              "example": {
                "targetOut": "50",
                "sendAsset": "sol",
                "payoutAsset": "usdc",
                "route": "relay"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/QuoteForOutput"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/RegionUnavailable"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/referral/create": {
      "post": {
        "operationId": "referralCreate",
        "summary": "Make a referral code",
        "description": "The key is shown once. Rate limit: 5 an hour.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReferralCreateRequest"
              },
              "example": {
                "payoutCoin": "zec",
                "payoutAddress": "<shielded Zcash address, u1...>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReferralCreated"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "code": "k7m2qx9p",
                    "key": "<64 hex characters>"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/AddressRefused"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/RegionUnavailable"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    },
    "/referral/check": {
      "post": {
        "operationId": "referralCheck",
        "summary": "Whether a referral code exists",
        "description": "Rate limit: 20 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReferralCheckRequest"
              },
              "example": {
                "code": "k7m2qx9p"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReferralCheck"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "valid": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/referral/stats": {
      "post": {
        "operationId": "referralStats",
        "summary": "Earnings for a code's secret key",
        "description": "Rate limit: 10 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReferralKeyRequest"
              },
              "example": {
                "key": "<64 hex characters>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReferralStats"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "code": "k7m2qx9p",
                    "payoutCoin": "zec",
                    "payoutAddressEnd": "q8x2kd",
                    "paidZec": "0.05000000",
                    "payoutMinimumZec": "0.05"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/referral/address": {
      "post": {
        "operationId": "referralAddress",
        "summary": "Change a code's payout address, proven with its key",
        "description": "Rate limit: 5 an hour.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReferralAddressRequest"
              },
              "example": {
                "key": "<64 hex characters>",
                "payoutAddress": "<new address on the code's coin>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ReferralAddress"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "code": "k7m2qx9p",
                    "payoutAddressEnd": "q8x2kd"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/AddressRefused"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "451": {
            "$ref": "#/components/responses/RegionUnavailable"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/rpc": {
      "post": {
        "operationId": "solanaRpc",
        "summary": "Solana JSON-RPC relay for the site's pay-from-wallet button",
        "description": "A narrow relay; most agents never need it (any Solana wallet or RPC can pay a deposit address). Answers in JSON-RPC 2.0, not wrapped. A send answers at a fixed time (about 2.5 s). Rate limit: 60 a minute.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RpcRequest"
              },
              "example": {
                "jsonrpc": "2.0",
                "id": 1,
                "method": "getBlockHeight"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The JSON-RPC answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RpcResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "502": {
            "description": "The RPC is unavailable right now.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RpcResponse"
                },
                "example": {
                  "jsonrpc": "2.0",
                  "id": 1,
                  "error": {
                    "code": -32000,
                    "message": "RPC unavailable"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/zpay/status": {
      "post": {
        "operationId": "zpayStatus",
        "summary": "Whether a shop's Z Pay links were paid",
        "description": "For a shop's server: up to 50 lookup keys per call, each answered with the best state across the swaps made for it. A completed payment shows at once; refunds and reviews from the next UTC day. A swap waiting for the payment, under way or expired is never shown, and nothing about the customer (wallet, coin or amount sent, route, times) is returned. Ship once the full amount shows in your own wallet. Never cached; not region-limited. Rate limit: 30 a minute. 404 while Z Pay is off.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZPayStatusRequest"
              },
              "example": {
                "keys": [
                  "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ZPayStatuses"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855": {
                      "state": "completed",
                      "swaps": 1,
                      "short": false,
                      "day": "2026-11-07"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/zpay/button/payments": {
      "post": {
        "operationId": "zpayButtonPayments",
        "summary": "A Z Pay button's dashboard: its recent finished payments",
        "description": "For the shop that owns the button (its secret key): completed payments newest first, then refunds and reviews (from the next UTC day), at most 100, from about the last 1-2 days, and which alerts are set. Nothing is listed while a payment is waiting or under way. A wrong key gets an empty list. Never cached. Rate limit: 30 a minute. 404 while Z Pay is off.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZPayButtonPaymentsRequest"
              },
              "example": {
                "key": "<43-character shop key>",
                "coin": "usdc",
                "to": "<the button's payout address>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ZPayButtonPayments"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "payments": [
                      {
                        "id": "q3kV9xT2mW8rL5nB1cZ7aY",
                        "amount": "25",
                        "state": "completed",
                        "short": false,
                        "at": "2026-11-07T12:41:00.000Z"
                      }
                    ],
                    "alerts": {
                      "discord": true,
                      "telegram": false
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/zpay/button": {
      "post": {
        "operationId": "zpayButtonAlerts",
        "summary": "Sets a Z Pay button's payment alerts (Discord, Telegram)",
        "description": "For the shop that owns the button (its secret key): a value sets an alert, null removes it, a field left out keeps it. Answers which alerts are set. One message per completed payment, sent to discord.com or api.telegram.org only. Rate limit: 10 a minute. 404 while Z Pay is off; 503 while new alerts take a short break.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ZPayButtonRequest"
              },
              "example": {
                "key": "<43-character shop key>",
                "coin": "usdc",
                "to": "<the button's payout address>",
                "discord": "https://discord.com/api/webhooks/<id>/<token>"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "success",
                    "data"
                  ],
                  "properties": {
                    "success": {
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/ZPayAlerts"
                    }
                  }
                },
                "example": {
                  "success": true,
                  "data": {
                    "discord": true,
                    "telegram": false
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "500": {
            "$ref": "#/components/responses/ServerError"
          },
          "503": {
            "$ref": "#/components/responses/Busy"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "success",
          "error"
        ],
        "properties": {
          "success": {
            "const": false
          },
          "error": {
            "type": "string",
            "description": "A message written for people: it can be shown as it is."
          },
          "issues": {
            "type": "array",
            "description": "Validation errors only (400): one entry per field.",
            "items": {
              "type": "object",
              "required": [
                "path",
                "message"
              ],
              "properties": {
                "path": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          },
          "code": {
            "type": "string",
            "enum": [
              "region_unavailable"
            ],
            "description": "451 only."
          }
        }
      },
      "Challenge": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "id",
          "exp",
          "bits",
          "sig"
        ],
        "description": "A proof-of-work challenge, sent back unchanged. Find a decimal nonce such that scrypt(password = id + nonce, salt = id, N = 16384, r = 8, p = 1, dkLen = 32), with both as UTF-8 text, starts with `bits` zero bits.",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "exp": {
            "type": "integer",
            "minimum": 1,
            "description": "Valid until this time, in milliseconds since 1970."
          },
          "bits": {
            "type": "integer",
            "minimum": 1,
            "maximum": 64,
            "description": "Leading zero bits the hash needs (at most 9 in practice)."
          },
          "sig": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          }
        }
      },
      "NoChallenge": {
        "type": "object",
        "required": [
          "bits"
        ],
        "properties": {
          "bits": {
            "const": 0
          }
        },
        "description": "Proof of work is off: send the deposit without challenge and nonce."
      },
      "Nonce": {
        "type": "string",
        "pattern": "^[0-9]{1,20}$",
        "description": "The decimal digits that solve the challenge."
      },
      "Info": {
        "type": "object",
        "properties": {
          "cluster": {
            "type": "string",
            "examples": [
              "mainnet-beta"
            ]
          },
          "simulated": {
            "type": "boolean",
            "description": "true only on a test deployment, where nothing real moves."
          },
          "feeBps": {
            "type": "integer",
            "description": "The Priva-Z fee on the private modes, in basis points."
          },
          "minAmount": {
            "type": "string",
            "description": "The smallest SOL amount any private route takes right now for SOL paid out. Missing for a moment after a restart."
          },
          "minAmounts": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Per payout coin: the smallest SOL deposit any private route takes to pay it."
          },
          "routeMinAmounts": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Per route, for SOL paid out."
          },
          "fast": {
            "type": "object",
            "required": [
              "available"
            ],
            "properties": {
              "available": {
                "type": "boolean"
              },
              "minAmount": {
                "type": "string"
              }
            },
            "description": "Whether Fast (route relay) is offered right now, with its minimum in SOL."
          },
          "maxAmount": {
            "type": "string",
            "description": "Only when the deployment sets a fixed SOL maximum."
          },
          "sendAssets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "payoutAssets": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "assets": {
            "type": "object",
            "additionalProperties": {
              "type": "object",
              "properties": {
                "symbol": {
                  "type": "string"
                },
                "network": {
                  "type": "string"
                },
                "inputDecimals": {
                  "type": "integer"
                },
                "max": {
                  "type": "string",
                  "description": "A technical ceiling per swap (coins a swap can start from only)."
                },
                "maxStated": {
                  "type": "boolean"
                }
              }
            }
          },
          "staggeredSplit": {
            "const": true,
            "description": "Present while the staggered split option is on."
          }
        }
      },
      "QuoteRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "amount"
        ],
        "properties": {
          "amount": {
            "type": "string",
            "maxLength": 20,
            "pattern": "^\\d+(\\.\\d+)?$",
            "description": "A decimal amount in the coin sent, e.g. \"1\" or \"0.5\". Round amounts: up to 2 decimals for SOL and LTC, 4 for BTC, 3 for ETH, whole USDT / USDC.",
            "examples": [
              "1"
            ]
          },
          "route": {
            "type": "string",
            "enum": [
              "relay",
              "zec",
              "xmr",
              "xmr-zec"
            ],
            "default": "zec",
            "description": "relay = Fast (two exchanges, Monero in between); zec = Zcash; xmr = Monero; xmr-zec = Both."
          },
          "referralCode": {
            "type": "string",
            "pattern": "^[A-Za-z0-9]{4,16}$",
            "description": "A referral code: 4-16 letters and digits, case-insensitive.",
            "examples": [
              "k7m2qx9p"
            ]
          },
          "payoutAsset": {
            "type": "string",
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc",
              "zec",
              "xmr"
            ],
            "default": "sol",
            "description": "The coin paid out. ZEC on the zec and xmr-zec routes, XMR on the xmr route. GET /info payoutAssets lists the coins on now."
          },
          "sendAsset": {
            "type": "string",
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc"
            ],
            "default": "sol",
            "description": "The coin sent. GET /info sendAssets lists the coins on now."
          },
          "separateExchanges": {
            "type": "boolean",
            "description": "A different exchange for each step. Left out: on by default where it costs at most about 0.3% more."
          },
          "includeFast": {
            "type": "boolean",
            "description": "Also list Fast (relay) in routes."
          },
          "avoidExchange": {
            "type": "string",
            "description": "An exchange id, as a quote's providers name it, to keep out of the swap. Used only while the quote offers that choice (exchangeChoice); otherwise ignored."
          }
        }
      },
      "RouteQuote": {
        "type": "object",
        "required": [
          "route",
          "available"
        ],
        "properties": {
          "route": {
            "type": "string",
            "enum": [
              "relay",
              "zec",
              "xmr",
              "xmr-zec"
            ]
          },
          "available": {
            "type": "boolean"
          },
          "providers": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The exchange for each step."
          },
          "minAmount": {
            "type": "string",
            "description": "In the coin sent."
          },
          "maxAmount": {
            "type": "string",
            "description": "In the coin sent, where an exchange states a maximum."
          },
          "estimatedOut": {
            "type": "string",
            "description": "What arrives, in the payout coin."
          },
          "estimatedSolBack": {
            "type": "string"
          },
          "totalCostPct": {
            "type": "number",
            "description": "All costs as a percent of what goes in, where known."
          },
          "separate": {
            "type": "boolean"
          },
          "reason": {
            "type": "string",
            "description": "Why this route can not take this amount right now (written for people)."
          }
        }
      },
      "Quote": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "amount",
          "fee",
          "net",
          "route",
          "feeBps",
          "simulated",
          "sendAsset",
          "payoutAsset"
        ],
        "properties": {
          "amount": {
            "type": "string"
          },
          "fee": {
            "type": "string"
          },
          "net": {
            "type": "string"
          },
          "route": {
            "type": "string",
            "enum": [
              "relay",
              "zec",
              "xmr",
              "xmr-zec"
            ]
          },
          "feeBps": {
            "type": "integer",
            "description": "The fee rate that applies to this quote (0 on Fast: its cost is in the exchange rates)."
          },
          "friendRate": {
            "const": true
          },
          "simulated": {
            "type": "boolean"
          },
          "sendAsset": {
            "type": "string"
          },
          "payoutAsset": {
            "type": "string"
          },
          "routes": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RouteQuote"
            }
          },
          "provider": {
            "type": "string"
          },
          "minAmount": {
            "type": "string",
            "description": "In the coin sent."
          },
          "maxAmount": {
            "type": "string",
            "description": "In the coin sent."
          },
          "estimatedOut": {
            "type": "string",
            "description": "What arrives, in the payout coin."
          },
          "estimatedSolBack": {
            "type": "string"
          },
          "estimatedZec": {
            "type": "string"
          },
          "separateExchanges": {
            "type": "boolean",
            "description": "Applied to this quote."
          },
          "separateDefault": {
            "type": "boolean"
          },
          "separateOption": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "properties": {
              "available": {
                "type": "boolean"
              },
              "providers": {
                "type": "array",
                "items": {
                  "type": "string"
                }
              },
              "estimatedOut": {
                "type": "string"
              },
              "extraCostPct": {
                "type": "number"
              },
              "reason": {
                "type": "string"
              }
            }
          },
          "breakdown": {
            "type": "object",
            "additionalProperties": true,
            "properties": {
              "legs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "from": {
                      "type": "string"
                    },
                    "to": {
                      "type": "string"
                    },
                    "provider": {
                      "type": "string"
                    },
                    "costPct": {
                      "type": [
                        "number",
                        "null"
                      ]
                    }
                  }
                }
              },
              "keptBackPct": {
                "type": "number",
                "description": "Kept back for network fees and privacy rounding."
              },
              "feePct": {
                "type": "number"
              },
              "totalPct": {
                "type": "number"
              }
            }
          },
          "exchangeChoice": {
            "type": "object",
            "properties": {
              "avoided": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "extraCostPct": {
                "type": [
                  "number",
                  "null"
                ]
              }
            }
          },
          "routeError": {
            "type": "string",
            "description": "Why the chosen route can not be quoted right now."
          }
        }
      },
      "DepositRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "amount",
          "returnAddress"
        ],
        "properties": {
          "amount": {
            "type": "string",
            "maxLength": 20,
            "pattern": "^\\d+(\\.\\d+)?$",
            "description": "What the user will send, in sendAsset.",
            "examples": [
              "1"
            ]
          },
          "returnAddress": {
            "type": "string",
            "minLength": 26,
            "maxLength": 500,
            "description": "The payout address on payoutAsset's network: brand-new and the user's own, never the sending wallet."
          },
          "privacyMode": {
            "type": "string",
            "enum": [
              "fast",
              "standard",
              "max",
              "extended",
              "crowd"
            ],
            "default": "standard",
            "description": "The random privacy wait on the private modes: fast (Short) 1-3 min, standard 5-30 min, max 30 min-3 h, extended 6-48 h, crowd until at least 3 other swaps have passed through (up to about 12 h). On fast or standard, the wait in Monero (route xmr, and the Monero step of xmr-zec) lasts about 40-70 minutes, its confirmations included."
          },
          "route": {
            "type": "string",
            "enum": [
              "relay",
              "zec",
              "xmr",
              "xmr-zec"
            ],
            "default": "zec",
            "description": "relay = Fast (two exchanges, Monero in between); zec = Zcash; xmr = Monero; xmr-zec = Both."
          },
          "splitPayout": {
            "type": "boolean",
            "default": false,
            "description": "Private modes: pay out in 2-3 uneven payments with waits between them."
          },
          "extraReturnAddresses": {
            "type": "array",
            "maxItems": 4,
            "default": [],
            "items": {
              "type": "string",
              "minLength": 26,
              "maxLength": 500
            },
            "description": "Up to 4 more payout addresses (with splitPayout). All addresses must differ."
          },
          "payoutPercents": {
            "type": "array",
            "minItems": 2,
            "maxItems": 5,
            "items": {
              "type": "integer",
              "minimum": 5,
              "maximum": 95
            },
            "description": "One whole percent per wallet, main address first, adding up to 100 (with extraReturnAddresses)."
          },
          "staggeredSplit": {
            "type": "boolean",
            "description": "Split payout only, while GET /info has staggeredSplit: each part at its own time within one privacy wait."
          },
          "referralCode": {
            "type": "string",
            "pattern": "^[A-Za-z0-9]{4,16}$",
            "description": "A referral code: 4-16 letters and digits, case-insensitive.",
            "examples": [
              "k7m2qx9p"
            ]
          },
          "payoutAsset": {
            "type": "string",
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc",
              "zec",
              "xmr"
            ],
            "default": "sol",
            "description": "The coin paid out. ZEC on the zec and xmr-zec routes, XMR on the xmr route. GET /info payoutAssets lists the coins on now."
          },
          "sendAsset": {
            "type": "string",
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc"
            ],
            "default": "sol",
            "description": "The coin sent. GET /info sendAssets lists the coins on now."
          },
          "separateExchanges": {
            "type": "boolean",
            "description": "A different exchange for each step. Left out: on by default where it costs at most about 0.3% more."
          },
          "avoidExchange": {
            "type": "string",
            "description": "An exchange id, as a quote's providers name it, to keep out of the swap. Used only while the quote offers that choice (exchangeChoice); otherwise ignored."
          },
          "refundAddress": {
            "type": "string",
            "minLength": 26,
            "maxLength": 120,
            "description": "The user's own address on sendAsset's network. Required for every coin but SOL, and for every coin on relay. Must not be a payout address."
          },
          "challenge": {
            "$ref": "#/components/schemas/Challenge"
          },
          "nonce": {
            "$ref": "#/components/schemas/Nonce"
          },
          "zpay": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "v",
              "pid",
              "exp",
              "amount"
            ],
            "description": "Only when paying a Z Pay link: its terms exactly as written in the link (the payout coin and address are this swap's own payoutAsset and returnAddress, which must be the link's coin and to). A Z Pay swap takes one payout address (no split, no referral code), a refundAddress on every coin, and privacyMode fast or standard only. 409 when the link is already paid or on its way, or was tried 3 times; 503 while new Z Pay payments take a short break.",
            "properties": {
              "v": {
                "const": 1
              },
              "pid": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{22,43}$",
                "description": "The link's payment id."
              },
              "exp": {
                "type": "string",
                "pattern": "^[1-9]\\d{0,11}$",
                "description": "The link's end, in Unix seconds: later than now and at most 24 hours ahead."
              },
              "amount": {
                "type": "string",
                "maxLength": 20,
                "description": "The amount the link asks for, in the payout coin, as the link writes it."
              },
              "btn": {
                "type": "string",
                "pattern": "^[A-Za-z0-9_-]{22}$",
                "description": "On links a Z Pay button makes: the button's public id."
              }
            }
          }
        }
      },
      "Deposit": {
        "type": "object",
        "required": [
          "depositId",
          "note",
          "depositAddress",
          "amount",
          "fee",
          "net",
          "route",
          "sendAsset",
          "payoutAsset",
          "separateExchanges",
          "simulated"
        ],
        "properties": {
          "depositId": {
            "type": "string",
            "format": "uuid"
          },
          "note": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "The secret note: the user's only receipt. Show it to the user; never store, log or send it anywhere else."
          },
          "depositAddress": {
            "type": "string",
            "description": "SOL on a private route: the one-time address to pay. Otherwise empty: poll POST /swap/deposit/status for the first exchange's address."
          },
          "amount": {
            "type": "string"
          },
          "fee": {
            "type": "string"
          },
          "net": {
            "type": "string"
          },
          "route": {
            "type": "string",
            "enum": [
              "relay",
              "zec",
              "xmr",
              "xmr-zec"
            ]
          },
          "sendAsset": {
            "type": "string"
          },
          "payoutAsset": {
            "type": "string"
          },
          "separateExchanges": {
            "type": "boolean"
          },
          "staggered": {
            "const": true
          },
          "simulated": {
            "type": "boolean"
          }
        }
      },
      "DepositStatus": {
        "type": "object",
        "additionalProperties": true,
        "required": [
          "depositId",
          "status"
        ],
        "properties": {
          "depositId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "CONFIRMED",
              "SWAPPING",
              "ZEC_HOLDING",
              "BRIDGING",
              "EXIT_HOLDING",
              "RETURNING",
              "COMPLETED",
              "FAILED"
            ]
          },
          "route": {
            "type": "string",
            "enum": [
              "relay",
              "zec",
              "xmr",
              "xmr-zec"
            ]
          },
          "sendAsset": {
            "type": "string"
          },
          "payoutAsset": {
            "type": "string"
          },
          "depositAddress": {
            "type": [
              "string",
              "null"
            ],
            "description": "Where to pay. For other coins and Fast: null until the first exchange's address is ready; null again once the payment is taken in."
          },
          "entryExchange": {
            "type": [
              "string",
              "null"
            ]
          },
          "entryExpiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "expiresAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "While unpaid: when the payment window closes."
          },
          "entryNotOrdered": {
            "type": "boolean"
          },
          "entryNotOrderedReason": {
            "const": "address"
          },
          "entryOutcome": {
            "type": [
              "string",
              "null"
            ]
          },
          "amount": {
            "type": "string"
          },
          "fee": {
            "type": "string"
          },
          "net": {
            "type": "string"
          },
          "directPayout": {
            "type": "boolean",
            "description": "ZEC or XMR paid straight out, with no last exchange step."
          },
          "separateExchanges": {
            "type": "boolean"
          },
          "depositTxHash": {
            "type": [
              "string",
              "null"
            ]
          },
          "failedLeg": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "first",
              "mid",
              "last",
              null
            ]
          },
          "swap1Status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "waiting",
              "confirming",
              "exchanging",
              "sending",
              "finished",
              "refunded",
              "failed",
              "expired",
              "simulated",
              null
            ]
          },
          "swapMidStatus": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "waiting",
              "confirming",
              "exchanging",
              "sending",
              "finished",
              "refunded",
              "failed",
              "expired",
              "simulated",
              null
            ]
          },
          "swap2Status": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "waiting",
              "confirming",
              "exchanging",
              "sending",
              "finished",
              "refunded",
              "failed",
              "expired",
              "simulated",
              null
            ]
          },
          "privacyMode": {
            "type": "string",
            "enum": [
              "fast",
              "standard",
              "max",
              "extended",
              "crowd"
            ]
          },
          "splitParts": {
            "type": "integer"
          },
          "splitDone": {
            "type": "integer"
          },
          "fixedShares": {
            "const": true
          },
          "holdUntil": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "During a privacy wait: until when."
          },
          "crowdWait": {
            "type": "boolean"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "completedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "confirmedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "receivedSol": {
            "type": [
              "string",
              "null"
            ]
          },
          "received": {
            "type": [
              "string",
              "null"
            ]
          },
          "resolution": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "refund_pending",
              "refunded",
              "recovered",
              null
            ]
          },
          "funded": {
            "type": "boolean"
          },
          "selfFunded": {
            "type": "boolean",
            "description": "Paid from one of its own payout addresses: a link the swap can not hide."
          },
          "refundClaim": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "available",
              "retry",
              "claimed",
              "review",
              "support",
              "sent",
              null
            ],
            "description": "POST /swap/status only."
          }
        }
      },
      "ArchivedStatus": {
        "type": "object",
        "required": [
          "status",
          "resolution",
          "archived"
        ],
        "description": "A finished swap whose record was cleared: only how it ended.",
        "properties": {
          "depositId": {
            "type": "string",
            "format": "uuid"
          },
          "status": {
            "type": "string",
            "enum": [
              "COMPLETED",
              "FAILED"
            ]
          },
          "resolution": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "refunded",
              "recovered",
              null
            ]
          },
          "archived": {
            "const": true
          }
        }
      },
      "DepositStatusRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "depositId"
        ],
        "properties": {
          "depositId": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "NoteRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "note"
        ],
        "properties": {
          "note": {
            "type": "string",
            "pattern": "^[0-9a-fA-F]{64}$",
            "description": "The secret note."
          }
        }
      },
      "RefundClaimRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "note",
          "refundAddress",
          "challenge",
          "nonce"
        ],
        "properties": {
          "note": {
            "type": "string",
            "pattern": "^[0-9a-fA-F]{64}$",
            "description": "The secret note."
          },
          "depositId": {
            "type": "string",
            "format": "uuid",
            "description": "Optional: must match the note's swap."
          },
          "refundAddress": {
            "type": "string",
            "minLength": 32,
            "maxLength": 44,
            "description": "The user's own Solana address."
          },
          "challenge": {
            "$ref": "#/components/schemas/Challenge"
          },
          "nonce": {
            "$ref": "#/components/schemas/Nonce"
          }
        }
      },
      "RefundClaim": {
        "type": "object",
        "required": [
          "claimed"
        ],
        "properties": {
          "claimed": {
            "const": true
          },
          "review": {
            "const": true,
            "description": "A person checks it before it is sent."
          }
        }
      },
      "PayCheckRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "address",
          "lamports"
        ],
        "properties": {
          "address": {
            "type": "string",
            "minLength": 32,
            "maxLength": 44,
            "description": "A Solana deposit address."
          },
          "lamports": {
            "type": "string",
            "pattern": "^[1-9]\\d{0,19}$"
          }
        }
      },
      "PayCheck": {
        "type": "object",
        "required": [
          "ok"
        ],
        "properties": {
          "ok": {
            "type": "boolean"
          }
        }
      },
      "QuoteForOutputRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "targetOut",
          "sendAsset",
          "payoutAsset",
          "route"
        ],
        "properties": {
          "targetOut": {
            "type": "string",
            "maxLength": 20,
            "pattern": "^\\d+(\\.\\d+)?$",
            "description": "The amount requested, in payoutAsset. Decimals: SOL 4, BTC 6, ETH 5, LTC 4, USDT 2, USDC 2, ZEC 6, XMR 6."
          },
          "sendAsset": {
            "type": "string",
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc"
            ]
          },
          "payoutAsset": {
            "type": "string",
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc",
              "zec",
              "xmr"
            ]
          },
          "route": {
            "type": "string",
            "enum": [
              "relay",
              "zec",
              "xmr",
              "xmr-zec"
            ]
          },
          "privacyMode": {
            "type": "string",
            "enum": [
              "fast",
              "standard",
              "max",
              "extended",
              "crowd"
            ],
            "description": "Accepted for the swap that follows; it does not change the amount."
          }
        }
      },
      "QuoteForOutput": {
        "type": "object",
        "required": [
          "status",
          "bufferPct",
          "evaluations",
          "simulated"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "below-minimum",
              "above-maximum",
              "unavailable"
            ]
          },
          "sendAsset": {
            "type": "string"
          },
          "payoutAsset": {
            "type": "string"
          },
          "route": {
            "type": "string"
          },
          "targetOut": {
            "type": "string"
          },
          "sendAmount": {
            "type": "string",
            "description": "ok: the amount to send."
          },
          "estimatedOut": {
            "type": "string"
          },
          "totalCostPct": {
            "type": "number"
          },
          "minAmount": {
            "type": "string",
            "description": "below-minimum."
          },
          "estimatedOutAtMin": {
            "type": "string"
          },
          "maxAmount": {
            "type": "string",
            "description": "above-maximum."
          },
          "estimatedOutAtMax": {
            "type": "string"
          },
          "reason": {
            "type": "string",
            "description": "unavailable."
          },
          "bufferPct": {
            "type": "number",
            "description": "The cushion added to the request."
          },
          "evaluations": {
            "type": "integer"
          },
          "simulated": {
            "type": "boolean"
          }
        }
      },
      "ReferralCreateRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "payoutCoin",
          "payoutAddress"
        ],
        "properties": {
          "payoutCoin": {
            "type": "string",
            "enum": [
              "zec",
              "sol"
            ]
          },
          "payoutAddress": {
            "type": "string",
            "minLength": 32,
            "maxLength": 300,
            "description": "A shielded Zcash address (u1... or zs1...) or a Solana address."
          }
        }
      },
      "ReferralCreated": {
        "type": "object",
        "required": [
          "code",
          "key"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "key": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$",
            "description": "Shown once: the only way to see earnings. Give it to the user; never keep it."
          }
        }
      },
      "ReferralCheckRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "code"
        ],
        "properties": {
          "code": {
            "type": "string",
            "pattern": "^[A-Za-z0-9]{4,16}$"
          }
        }
      },
      "ReferralCheck": {
        "type": "object",
        "required": [
          "valid"
        ],
        "properties": {
          "valid": {
            "type": "boolean"
          }
        }
      },
      "ReferralKeyRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "key"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[0-9a-fA-F]{64}$",
            "description": "The code's secret key."
          }
        }
      },
      "ReferralStats": {
        "type": "object",
        "required": [
          "code",
          "payoutCoin",
          "payoutAddressEnd",
          "paidZec",
          "payoutMinimumZec"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "payoutCoin": {
            "type": "string",
            "enum": [
              "zec",
              "sol"
            ]
          },
          "payoutAddressEnd": {
            "type": "string",
            "description": "The last 6 characters."
          },
          "paidZec": {
            "type": "string",
            "description": "Paid so far, rounded down to 0.005 ZEC."
          },
          "payoutMinimumZec": {
            "type": "string"
          }
        }
      },
      "ReferralAddressRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "key",
          "payoutAddress"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[0-9a-fA-F]{64}$",
            "description": "The code's secret key."
          },
          "payoutAddress": {
            "type": "string",
            "minLength": 32,
            "maxLength": 300
          }
        }
      },
      "ReferralAddress": {
        "type": "object",
        "required": [
          "code",
          "payoutAddressEnd"
        ],
        "properties": {
          "code": {
            "type": "string"
          },
          "payoutAddressEnd": {
            "type": "string"
          }
        }
      },
      "RpcRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "jsonrpc",
          "id",
          "method"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 64
              },
              {
                "type": "number"
              }
            ]
          },
          "method": {
            "type": "string",
            "maxLength": 40,
            "description": "getLatestBlockhash, getSignatureStatuses (one signature), getBlockHeight, getBalance, or sendTransaction (base64; a plain SOL transfer into an open Priva-Z deposit address only)."
          },
          "params": {
            "type": "array",
            "maxItems": 4
          }
        }
      },
      "RpcResponse": {
        "type": "object",
        "required": [
          "jsonrpc",
          "id"
        ],
        "properties": {
          "jsonrpc": {
            "const": "2.0"
          },
          "id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "number"
              }
            ]
          },
          "result": {},
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "integer"
              },
              "message": {
                "type": "string"
              }
            }
          }
        }
      },
      "ZPayStatusRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "keys"
        ],
        "properties": {
          "keys": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "type": "string",
              "pattern": "^[0-9a-f]{64}$"
            },
            "description": "Lookup keys: sha256_hex(\"privaz-zpay|1|\" + coin + \"|\" + amount + \"|\" + to + \"|\" + pid + \"|\" + exp), lowercase, over the link's values exactly as written."
          }
        }
      },
      "ZPayStatus": {
        "type": "object",
        "required": [
          "state",
          "swaps"
        ],
        "properties": {
          "state": {
            "enum": [
              "none",
              "completed",
              "refunded",
              "review"
            ],
            "description": "completed: the payout was sent (shown at once). refunded: the payment went back to the customer; review: settled by hand (both shown from the next UTC day). none: nothing to show yet, or the records were already deleted (about a day after the swap finished)."
          },
          "swaps": {
            "type": "integer",
            "minimum": 0,
            "description": "How many swaps for this key are shown."
          },
          "short": {
            "type": "boolean",
            "description": "Where the route checked the amount: true, less than asked arrived (not paid in full); false, the full amount arrived."
          },
          "checked": {
            "const": false,
            "description": "On a completed payment whose route couldn't check the amount: see your wallet for what arrived."
          },
          "day": {
            "type": "string",
            "format": "date",
            "description": "The UTC day the swap finished."
          }
        }
      },
      "ZPayStatuses": {
        "type": "object",
        "additionalProperties": {
          "$ref": "#/components/schemas/ZPayStatus"
        },
        "description": "One entry per key asked."
      },
      "ZPayButtonPaymentsRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "key",
          "coin",
          "to"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "The shop's secret key, made in the shop's browser (never the button's public id)."
          },
          "coin": {
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc",
              "zec",
              "xmr"
            ],
            "description": "The button's payout coin."
          },
          "to": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The button's payout address, as its links write it."
          }
        }
      },
      "ZPayButtonPayments": {
        "type": "object",
        "required": [
          "payments",
          "alerts"
        ],
        "properties": {
          "payments": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "type": "object",
              "required": [
                "id",
                "amount",
                "state"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "A stable id for the payment (not the swap's)."
                },
                "amount": {
                  "type": "string",
                  "description": "The amount the link asked for."
                },
                "state": {
                  "enum": [
                    "completed",
                    "refunded",
                    "review"
                  ]
                },
                "short": {
                  "type": "boolean"
                },
                "checked": {
                  "const": false
                },
                "at": {
                  "type": "string",
                  "format": "date-time",
                  "description": "On completed only: when it completed, to the minute."
                }
              }
            }
          },
          "alerts": {
            "$ref": "#/components/schemas/ZPayAlerts"
          }
        }
      },
      "ZPayButtonRequest": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "key",
          "coin",
          "to"
        ],
        "properties": {
          "key": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_-]{43}$",
            "description": "The shop's secret key, made in the shop's browser (never the button's public id)."
          },
          "coin": {
            "enum": [
              "sol",
              "btc",
              "eth",
              "usdt",
              "usdc",
              "ltc",
              "zec",
              "xmr"
            ],
            "description": "The button's payout coin."
          },
          "to": {
            "type": "string",
            "minLength": 1,
            "maxLength": 200,
            "description": "The button's payout address, as its links write it."
          },
          "discord": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 200,
            "description": "A Discord webhook URL (https://discord.com/api/webhooks/<id>/<token>) to set, null to remove it; left out, it stays as it is."
          },
          "telegram": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": false,
            "required": [
              "token",
              "chat"
            ],
            "properties": {
              "token": {
                "type": "string",
                "maxLength": 80,
                "description": "A bot token from @BotFather."
              },
              "chat": {
                "type": "string",
                "maxLength": 40,
                "description": "A numeric chat id or a public @channel."
              }
            },
            "description": "A Telegram bot and chat to set, null to remove it; left out, it stays as it is."
          }
        }
      },
      "ZPayAlerts": {
        "type": "object",
        "required": [
          "discord",
          "telegram"
        ],
        "properties": {
          "discord": {
            "type": "boolean"
          },
          "telegram": {
            "type": "boolean"
          }
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request needs a fix. Validation errors carry issues, one per field.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Amount must be a positive number, like 1 or 0.5",
              "issues": [
                {
                  "path": "amount",
                  "message": "Amount must be a positive number, like 1 or 0.5"
                }
              ]
            }
          }
        }
      },
      "AddressRefused": {
        "description": "An address is on the sanctions list or a law-enforcement list of stolen funds. Stop; do not retry with it.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "This address can't be used with Priva-Z."
            }
          }
        }
      },
      "NotFound": {
        "description": "Not found (or a feature that is switched off).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Not found"
            }
          }
        }
      },
      "Conflict": {
        "description": "A challenge already used, or a change that conflicts with one under way.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "That challenge was already used: please request a new one"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Too many requests: wait, then retry slowly.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Too many requests, please try again later"
            }
          }
        }
      },
      "RegionUnavailable": {
        "description": "New swaps are not offered in the caller's region.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Priva-Z isn't available in your region.",
              "code": "region_unavailable"
            }
          }
        }
      },
      "ServerError": {
        "description": "Internal server error: retry later.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Internal server error"
            }
          }
        }
      },
      "Busy": {
        "description": "Busy for a moment: retry shortly.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            },
            "example": {
              "success": false,
              "error": "Busy right now — please try again shortly"
            }
          }
        }
      }
    }
  }
}
