{
  "openapi": "3.0.0",
  "paths": {
    "/v1/health/liveness": {
      "get": {
        "description": "Answers `{ \"status\": \"ok\" }` while the process is up, without checking any dependency, the database included. Public: no API key, for the orchestrator to probe directly.",
        "operationId": "HealthController_liveness_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "The process is up. It says nothing about the database.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Liveness probe",
        "tags": [
          "health"
        ],
        "x-cosmos-public": true,
        "security": []
      }
    },
    "/v1/health/readiness": {
      "get": {
        "description": "Pings Postgres: 200 with the indicator report when it answers, `503 provider_unavailable` when it does not, with a body that names no host or cause (those are only logged). Public: no API key, for the orchestrator to probe directly.",
        "operationId": "HealthController_readiness_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "Every indicator is up; the service can take traffic.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": {
                      "type": "string",
                      "example": "ok"
                    },
                    "info": {
                      "type": "object",
                      "example": {
                        "database": {
                          "status": "up"
                        }
                      }
                    },
                    "error": {
                      "type": "object",
                      "example": {}
                    },
                    "details": {
                      "type": "object",
                      "example": {
                        "database": {
                          "status": "up"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "An indicator is down: today that means Postgres did not answer the ping. Which one, and why, is logged; the body says only that the service is not ready, because this route is served without credentials and the indicator report names internal hosts.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: an indicator is down",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "Service Unavailable Exception",
                      "path": "/v1/health/readiness",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Readiness probe (checks the database)",
        "tags": [
          "health"
        ],
        "x-cosmos-public": true,
        "security": []
      }
    },
    "/v1/payment-intents/tx": {
      "post": {
        "description": "Stellar only: builds the unsigned envelope paying `destination` from `source` on the key's network (a `prod` key builds for mainnet, a `dev` key for testnet), plus a second payment to `merchantFee.wallet` when a merchant fee is set, and answers its XDR, `web+stellar:tx` URI and QR. `memo` (a numeric MEMO_ID, generated when omitted) is the idempotency key: a retry with the same memo and terms returns the stored intent, other terms are `409 idempotency_conflict`. The intent starts `PENDING`, emits `PAYMENT_INTENT_CREATED`, and the on-chain observer settles it when the payment lands.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "PaymentIntentsController_createTx_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTxPaymentIntentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TxPaymentIntentEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`trustline_missing`: the destination does not trust the issued asset being paid. The payer signs this transaction and the destination signs nothing, so only the destination account can add the trustline.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_memo": {
                    "summary": "invalid_memo: The memo is not the type this route requires",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_memo",
                      "error": "Bad Request",
                      "message": "memo must be a MEMO_ID: a numeric uint64",
                      "path": "/v1/payment-intents/pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, so it cannot receive the swap. Only that account can add the trustline, by signing a transaction of its own: ask its owner to add it, then try again.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "insufficient_balance": {
                    "summary": "insufficient_balance: The source account cannot cover the amount, or the XLM reserve the transaction needs",
                    "value": {
                      "statusCode": 400,
                      "code": "insufficient_balance",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ holds only 12.5000000 shares of this pool",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`idempotency_conflict`: an intent with this `memo` already exists for different payment details. Retry with the original request unchanged, or use a new memo (omit `memo` to have one generated). `operation_in_flight`: a concurrent create for the same memo changed it while this one was being created; retry the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A withdrawal from this pool is already in flight for this account. Wait for it to settle or expire before starting another: the commission on a withdrawal depends on the position it leaves behind.",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Create a SEP-7 `tx` intent (source known → unsigned XDR + tx URI + QR)",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "payment-intents:build",
            "limit": 30,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/payment-intents/pay": {
      "post": {
        "description": "Answers a link any wallet can pay and its QR: SEP-7 `web+stellar:pay` on Stellar (the default `chain`), Solana Pay on Solana, EIP-681 on Monad, on the key's network (a `prod` key gets mainnet, a `dev` key the test networks). Omit `amount` for an open amount, except on Monad when this deployment has no deposit addresses; with a `merchantFee`, `uri` is the hosted checkout on Stellar and a Solana Pay transaction request on Solana. `memo` (numeric, generated when omitted) is the idempotency key: the same memo and terms return the stored intent, other terms are `409 idempotency_conflict`. Emits `PAYMENT_INTENT_CREATED`; the on-chain observer settles the intent when it finds the payment (a native MON payment without a deposit address needs `validate`).\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "PaymentIntentsController_createPay_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayPaymentIntentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayPaymentIntentEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`invalid_amount`: Not a Stellar amount, or not greater than zero\n\n`invalid_memo`: The memo is not the type this route requires",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_memo": {
                    "summary": "invalid_memo: The memo is not the type this route requires",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_memo",
                      "error": "Bad Request",
                      "message": "memo must be a MEMO_ID: a numeric uint64",
                      "path": "/v1/payment-intents/pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`idempotency_conflict`: an intent with this `memo` already exists for different payment details. Retry with the original request unchanged, or use a new memo (omit `memo` to have one generated). `operation_in_flight`: a concurrent create for the same memo changed it while this one was being created; retry the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A withdrawal from this pool is already in flight for this account. Wait for it to settle or expire before starting another: the commission on a withdrawal depends on the position it leaves behind.",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a `pay` intent: a payment link and QR on Stellar, Solana or Monad",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "payment-intents:build",
            "limit": 30,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Solana",
          "Monad"
        ]
      }
    },
    "/v1/payment-intents": {
      "get": {
        "description": "Newest first, as `{ data, total, take, skip }` with `take` up to 100 (default 20). Only intents on the key's network (a `prod` key lists mainnet intents, a `dev` key test-network ones), narrowed by `status`, `chain` and `createdFrom` when given.\n\nRequires the `payments:read` scope.",
        "operationId": "PaymentIntentsController_findAll_v1",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only intents in this status. Omit for every status.",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "SUBMITTED",
                "SUCCEEDED",
                "FAILED",
                "CANCELLED",
                "EXPIRED"
              ]
            }
          },
          {
            "name": "chain",
            "required": false,
            "in": "query",
            "description": "Only intents on this chain. Omit for every chain.",
            "schema": {
              "type": "string",
              "enum": [
                "stellar",
                "solana",
                "monad"
              ]
            }
          },
          {
            "name": "createdFrom",
            "required": false,
            "in": "query",
            "description": "Only intents created at or after this instant (ISO 8601). Omit for no lower bound. The dashboard uses it for its today / week / month / year views of the list.",
            "schema": {
              "format": "date-time",
              "example": "2026-10-01T00:00:00.000Z",
              "type": "string"
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentIntentListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's payment intents",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/payment-intents/{id}/transitions": {
      "get": {
        "description": "The intent's audit trail as an array, oldest first: every status change with `fromStatus`, `toStatus`, the `txHash` it carried, its `reason` and the `actor` that made it (`api`, `validate`, `observer` or `system`).\n\nRequires the `payments:read` scope.",
        "operationId": "PaymentIntentsController_listTransitions_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": {
                    "$ref": "#/components/schemas/PaymentIntentTransitionEntity"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the status-transition history for a payment intent",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/payment-intents/{id}": {
      "get": {
        "description": "One of the consumer’s intents, on any chain, with its QR rebuilt from `uri`. `status` moves as the on-chain observer settles or expires the intent, which the `PAYMENT_INTENT_*` webhooks also report, so polling this route is optional.\n\nRequires the `payments:read` scope.",
        "operationId": "PaymentIntentsController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentIntentEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a payment intent by id",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      },
      "patch": {
        "description": "Send only what changes; `reference` and `checkoutTheme` are accepted in any status. `status: SUCCEEDED` needs a `txHash` and goes through the same on-chain check as `validate` (`400 transaction_rejected` when the chain does not confirm it); other status changes follow the transition graph (`SUCCEEDED`, `FAILED` and `CANCELLED` are final, `EXPIRED` only settles on a verified payment), else `400 invalid_state_transition`. A new `txHash` alone is accepted only while `PENDING` or `SUBMITTED`. Emits `PAYMENT_INTENT_CANCELLED`, `PAYMENT_INTENT_SUCCEEDED` or `PAYMENT_INTENT_FAILED` for those statuses and `PAYMENT_INTENT_UPDATED` otherwise.\n\nRequires the `payments:write` scope.",
        "operationId": "PaymentIntentsController_update_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdatePaymentIntentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PaymentIntentEntity"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`invalid_state_transition`: The resource cannot move to that state from the one it is in\n\n`transaction_rejected`: The submitted transaction does not do what the route needs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "txHash cannot be changed on a SUCCEEDED payment intent: the status is terminal",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "transaction_rejected": {
                    "summary": "transaction_rejected: The submitted transaction does not do what the route needs",
                    "value": {
                      "statusCode": 400,
                      "code": "transaction_rejected",
                      "error": "Bad Request",
                      "message": "The transaction does not settle this payment intent: the amount paid is below the amount requested",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2/validate",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`transaction_already_settled`: the transaction already settled, or also pays an older, payment intent of any consumer, and one payment settles at most one intent, the oldest it pays; this intent is not paid by it. `idempotency_conflict`: the hash is already recorded on another of your intents. `operation_in_flight`: the status changed under this request; re-read the intent and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "transaction_already_settled": {
                    "summary": "transaction_already_settled: That transaction settles another payment intent",
                    "value": {
                      "statusCode": 409,
                      "code": "transaction_already_settled",
                      "error": "Conflict",
                      "message": "This transaction settles another payment intent. One payment settles at most one intent: the oldest it pays.",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2/validate",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A withdrawal from this pool is already in flight for this account. Wait for it to settle or expire before starting another: the commission on a withdrawal depends on the position it leaves behind.",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Update a payment intent (status / txHash / reference / checkoutTheme)",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Horizon",
          "Solana",
          "Monad"
        ]
      },
      "delete": {
        "description": "Deletes an intent in any status but `SUCCEEDED` and emits `PAYMENT_INTENT_DELETED`. A paid intent is a settled payment and cannot be deleted (`400 invalid_state_transition`); an intent whose status changes during the delete (it may have just been paid) is `409 operation_in_flight`.\n\nRequires the `payments:write` scope.",
        "operationId": "PaymentIntentsController_remove_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeletedEntity"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`invalid_state_transition`: The resource cannot move to that state from the one it is in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "txHash cannot be changed on a SUCCEEDED payment intent: the status is terminal",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`operation_in_flight`: the status changed under this delete. The intent may have just been paid. Re-read it before retrying.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A withdrawal from this pool is already in flight for this account. Wait for it to settle or expire before starting another: the commission on a withdrawal depends on the position it leaves behind.",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Delete a payment intent",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/payment-intents/{id}/validate": {
      "post": {
        "description": "Looks `txHash` up on the intent's chain and checks it pays this intent (success, destination, asset, amount, memo or reference, age); a match settles it `SUCCEEDED` and emits `PAYMENT_INTENT_SUCCEEDED`. This intent's own payment that failed on-chain marks it `FAILED` (`PAYMENT_INTENT_FAILED`); any other mismatch answers `valid: false` with a `reason` and leaves the status unchanged. An `EXPIRED` intent still settles on a verified payment, a `SUCCEEDED` one answers as it is without asking the chain, and one transaction settles at most one intent of any consumer (the oldest it pays).\n\nRequires the `payments:write` scope.",
        "operationId": "PaymentIntentsController_validate_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ValidatePaymentIntentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ValidationOutcomeEntity"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`transaction_rejected`: The submitted transaction does not do what the route needs\n\n`invalid_state_transition`: The resource cannot move to that state from the one it is in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "transaction_rejected": {
                    "summary": "transaction_rejected: The submitted transaction does not do what the route needs",
                    "value": {
                      "statusCode": 400,
                      "code": "transaction_rejected",
                      "error": "Bad Request",
                      "message": "The transaction does not settle this payment intent: the amount paid is below the amount requested",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2/validate",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "txHash cannot be changed on a SUCCEEDED payment intent: the status is terminal",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`transaction_already_settled`: the transaction already settled, or also pays an older, payment intent of any consumer, and one payment settles at most one intent, the oldest it pays; this intent is not paid by it. `idempotency_conflict`: the hash is already recorded on another of your intents. `operation_in_flight`: the status changed under this request; re-read the intent and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "transaction_already_settled": {
                    "summary": "transaction_already_settled: That transaction settles another payment intent",
                    "value": {
                      "statusCode": 409,
                      "code": "transaction_already_settled",
                      "error": "Conflict",
                      "message": "This transaction settles another payment intent. One payment settles at most one intent: the oldest it pays.",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2/validate",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A withdrawal from this pool is already in flight for this account. Wait for it to settle or expire before starting another: the commission on a withdrawal depends on the position it leaves behind.",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Validate a transaction against the intent and settle it",
        "tags": [
          "payment-intents"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Horizon",
          "Solana",
          "Monad"
        ]
      }
    },
    "/v1/payment-links/{id}": {
      "get": {
        "description": "For a hosted checkout page: amount, asset, network, the address to pay (`payTo`), the link and its QR, and the live status, so the page can poll until the payment settles. Reachable without an API key or the gateway secret.\n\n**The id is the capability.** Anyone who holds a payment link can read it here, which is what a payment link is for. Nothing about the owning merchant account, the payer’s own account, the envelope, the merchant’s `reference` or `callback`, or the status history is returned. `uri` is the link verbatim, so whatever the wallet needs from it is in it.\n\nAnswered with `Cache-Control: no-store`. Budgeted per client address (`x-cosmos-rate-limit`): poll at most every few seconds and honour `Retry-After`.",
        "operationId": "PaymentLinksController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The payment intent id (a cuid), as in the link `https://payments.cosmospay.lat/<id>`.",
            "schema": {
              "example": "cmh4x2k9a0001l70g8v5q3z2w",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              },
              "Cache-Control": {
                "description": "Always `no-store`: the status changes live.",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              }
            },
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicPaymentLinkEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "404": {
            "description": "No payment intent has this id: it never existed or it was deleted. The two are the same answer, and the same one `GET /v1/payment-intents/{id}` gives its owner.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No payment intent has this id",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w not found",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Read a payment link as its payer sees it (no API key)",
        "tags": [
          "payment-links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "payment-links:read",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "security": []
      }
    },
    "/v1/payment-links/{id}/transaction": {
      "post": {
        "description": "A SEP-7 `pay` link pays one account, so a Stellar payment link with a merchant fee (`payerAccountRequired` on the link) asks for its payer: given their account, this builds the unsigned envelope with both payments (to the merchant, and the fee to its wallet) and the link’s MEMO_ID, and its `web+stellar:tx` link and QR. The link settles on any transaction that pays both with the memo, so nothing is stored and a lapsed envelope is simply built again.\n\nOnly for an open link (`PENDING`). Budgeted per client address.",
        "operationId": "PaymentLinksController_transaction_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The payment intent id, as in the link.",
            "schema": {
              "example": "cmh4x2k9a0001l70g8v5q3z2w",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayerTransactionDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayerTransactionEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: the link pays its destination directly (open its `uri`), or `account` is not a Stellar account. `invalid_state_transition`: the link is no longer open. `trustline_missing`: the merchant no longer trusts the asset.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The link has its own wallet link",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "This payment link pays its destination directly: open its uri",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/transaction",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The link is no longer open",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w is EXPIRED: it can no longer be paid",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/transaction",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, so it cannot receive the swap. Only that account can add the trustline, by signing a transaction of its own: ask its owner to add it, then try again.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No payment intent has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No payment intent has this id",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w not found",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/transaction",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Build the envelope a payer signs for a Stellar link with a merchant fee (no API key)",
        "tags": [
          "payment-links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "payment-links:transaction",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ],
        "security": []
      }
    },
    "/v1/payment-links/{id}/events": {
      "post": {
        "description": "The hosted checkout tells what the payer did with a wallet while the link is pending: `walletOpened` (the wallet link, the web wallet, the extension or Freighter was opened), `walletClosed` (the wallet came back without paying) and `sent` (the page saw the wallet send the payment). The owner reads them as `checkoutWalletAt`, `checkoutWalletClosedAt` and `checkoutSentAt` on the intent, to follow a payment that is not on-chain yet.\n\n**Informational only:** the status changes on what the chain says, never on these. An event for a link that is no longer pending is ignored. Budgeted per client address.",
        "operationId": "PaymentLinksController_event_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The payment intent id, as in the link.",
            "schema": {
              "example": "cmh4x2k9a0001l70g8v5q3z2w",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CheckoutEventDto"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Noted (or ignored: the link is not pending).",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`event` is not one of the three.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: An unknown event",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "event must be one of the following values: walletOpened, walletClosed, sent",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/events",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No payment intent has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No payment intent has this id",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w not found",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/events",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Report what the payer did with a wallet from the hosted checkout (no API key)",
        "tags": [
          "payment-links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "payment-links:events",
            "limit": 30,
            "windowMs": 60000
          }
        ],
        "security": []
      }
    },
    "/v1/payment-links/{id}/solana-pay": {
      "get": {
        "description": "A Solana payment link with a merchant fee is a Solana Pay transaction request (`solana:<this URL>`), because a transfer request names one recipient. A wallet reads this first, then POSTs the payer’s account.",
        "operationId": "PaymentLinksController_solanaPayInfo_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The payment intent id.",
            "schema": {
              "example": "cmh4x2k9a0001l70g8v5q3z2w",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SolanaPayInfoEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: the link is not a Solana Pay transaction request (only a Solana link with a merchant fee is), or `account` is not a Solana address. `invalid_state_transition`: the link is no longer open.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: Not a transaction request",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "This payment link is not a Solana Pay transaction request: open its uri",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The link is no longer open",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w is EXPIRED: it can no longer be paid",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No payment intent has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No payment intent has this id",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w not found",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Solana Pay transaction request, GET: the label and icon a wallet shows (no API key)",
        "tags": [
          "payment-links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "payment-links:read",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "security": []
      },
      "post": {
        "description": "Given the payer’s `account`, the unsigned transaction (base64) with the link’s memo, the transfer to the merchant carrying the link’s reference, and the merchant fee’s transfer to its wallet (creating their token accounts first when missing, paid by the payer). The link settles from the ledger, found by its reference; nothing is stored. Only for an open link.",
        "operationId": "PaymentLinksController_solanaPayTransaction_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The payment intent id.",
            "schema": {
              "example": "cmh4x2k9a0001l70g8v5q3z2w",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SolanaPayAccountDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SolanaPayTransactionEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: the link is not a Solana Pay transaction request (only a Solana link with a merchant fee is), or `account` is not a Solana address. `invalid_state_transition`: the link is no longer open.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: Not a transaction request",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "This payment link is not a Solana Pay transaction request: open its uri",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The link is no longer open",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w is EXPIRED: it can no longer be paid",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No payment intent has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No payment intent has this id",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Payment intent cmh4x2k9a0001l70g8v5q3z2w not found",
                      "path": "/v1/payment-links/cmh4x2k9a0001l70g8v5q3z2w/solana-pay",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Solana Pay transaction request, POST: the transaction the payer signs (no API key)",
        "tags": [
          "payment-links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "payment-links:transaction",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Solana"
        ],
        "security": []
      }
    },
    "/v1/customers": {
      "post": {
        "description": "A customer holds up to 20 `wallets` on Stellar, Solana or Monad (the deprecated `account` counts as one of them), and a wallet named twice counts once. Payments settled from any of them count toward the customer. A wallet another of your customers already holds is `409 customer_wallet_taken`.\n\nRequires the `customers:write` scope.",
        "operationId": "CustomersController_create_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCustomerDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`customer_wallet_taken`: Another of your customers already holds that wallet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "customer_wallet_taken": {
                    "summary": "customer_wallet_taken: Another of your customers already holds that wallet",
                    "value": {
                      "statusCode": 409,
                      "code": "customer_wallet_taken",
                      "error": "Conflict",
                      "message": "The wallet GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO (stellar) already belongs to customer clz9xcust00002.",
                      "path": "/v1/customers/clz9xcust00001/wallets",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Create a customer",
        "tags": [
          "customers"
        ],
        "x-cosmos-scopes": [
          "customers:write"
        ]
      },
      "get": {
        "description": "Newest first, as `{ data, total, take, skip }` with `take` up to 100 (default 100). Each customer carries `payments`, `succeeded` and the gross settled `total` (amounts added as numbers, whatever the asset) of the payment intents paid from its wallets, on the key's network only. The payer of a settled payment whose wallet no customer holds is added automatically (`reference: auto`).\n\nRequires the `customers:read` scope.",
        "operationId": "CustomersController_findAll_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's customers (with payment stats)",
        "tags": [
          "customers"
        ],
        "x-cosmos-scopes": [
          "customers:read"
        ]
      }
    },
    "/v1/customers/{id}": {
      "get": {
        "description": "The customer with its wallets, oldest first, and `account`, the deprecated first wallet's address. Payment stats are on the list only.\n\nRequires the `customers:read` scope.",
        "operationId": "CustomersController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a customer by id",
        "tags": [
          "customers"
        ],
        "x-cosmos-scopes": [
          "customers:read"
        ]
      },
      "patch": {
        "description": "Changes only the fields sent (`name`, `alias`, `note`, `email`, `reference`). The deprecated `account` edits the first wallet only: an address replaces or adds it, `null` removes it; other wallets change through `/v1/customers/{id}/wallets`. An address another of your customers holds is `409 customer_wallet_taken`.\n\nRequires the `customers:write` scope.",
        "operationId": "CustomersController_update_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateCustomerDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`customer_wallet_taken`: Another of your customers already holds that wallet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "customer_wallet_taken": {
                    "summary": "customer_wallet_taken: Another of your customers already holds that wallet",
                    "value": {
                      "statusCode": 409,
                      "code": "customer_wallet_taken",
                      "error": "Conflict",
                      "message": "The wallet GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO (stellar) already belongs to customer clz9xcust00002.",
                      "path": "/v1/customers/clz9xcust00001/wallets",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Update a customer",
        "tags": [
          "customers"
        ],
        "x-cosmos-scopes": [
          "customers:write"
        ]
      },
      "delete": {
        "description": "Deletes the customer and its wallets. Payment intents are kept; a later settled payment from one of those wallets adds its payer back as an automatic customer.\n\nRequires the `customers:write` scope.",
        "operationId": "CustomersController_remove_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Delete a customer",
        "tags": [
          "customers"
        ],
        "x-cosmos-scopes": [
          "customers:write"
        ]
      }
    },
    "/v1/customers/{id}/wallets": {
      "post": {
        "description": "A customer holds any number of wallets (up to 20), on Stellar, Solana or Monad; payments paid from any of them count toward it. A wallet the customer already holds answers as it is.\n\nRequires the `customers:write` scope.",
        "operationId": "CustomersController_addWallet_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerWalletDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerWalletEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`customer_wallet_taken`: Another of your customers already holds that wallet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "customer_wallet_taken": {
                    "summary": "customer_wallet_taken: Another of your customers already holds that wallet",
                    "value": {
                      "statusCode": 409,
                      "code": "customer_wallet_taken",
                      "error": "Conflict",
                      "message": "The wallet GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO (stellar) already belongs to customer clz9xcust00002.",
                      "path": "/v1/customers/clz9xcust00001/wallets",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Add a wallet to a customer",
        "tags": [
          "customers"
        ],
        "x-cosmos-scopes": [
          "customers:write"
        ]
      }
    },
    "/v1/customers/{id}/wallets/{walletId}": {
      "delete": {
        "description": "Payments from that address stop counting toward this customer, and a later settled payment from it adds it as a new automatic customer. A `walletId` that is not one of this customer's wallets is 404.\n\nRequires the `customers:write` scope.",
        "operationId": "CustomersController_removeWallet_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "walletId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerWalletDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Remove a wallet from a customer",
        "tags": [
          "customers"
        ],
        "x-cosmos-scopes": [
          "customers:write"
        ]
      }
    },
    "/v1/swaps/quote": {
      "post": {
        "description": "Prices `amount` of the source asset on the chain's own venue: the Stellar DEX (a Horizon strict-send path search on the key's network) when `chain` is omitted or `stellar`, Jupiter for `solana` and Kuru Flow for `monad`, both mainnet only. The answer carries the plan commission (`fee`: taken from the source amount on Stellar, from the output on Solana and Monad), any `merchantFee`, the estimated output and the minimum after slippage. `slippageBps` defaults to 50 and a value above the cap (500) is `slippage_exceeded`, unless the deployment configures other values.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "SwapsController_quote_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteSwapDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SwapQuoteEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`network_unsupported`: `chain: solana | monad` with a dev (testnet) key: Jupiter and Kuru Flow run on mainnet only. `asset_unsupported`: not an SPL mint / ERC-20 on that chain. `provider_error`: the aggregator found no route or refused the amount. `merchant_fee_unsupported`: a `merchantFee` on a Monad swap where no merchant fee router is configured (KURU_MERCHANT_FEE_ROUTER).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "slippage_exceeded": {
                    "summary": "slippage_exceeded: The requested slippage is above what this service allows",
                    "value": {
                      "statusCode": 400,
                      "code": "slippage_exceeded",
                      "error": "Bad Request",
                      "message": "slippageBps 900 exceeds the maximum allowed (500)",
                      "path": "/v1/swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "no_path_found": {
                    "summary": "no_path_found: Horizon found no payment path for this pair and amount",
                    "value": {
                      "statusCode": 400,
                      "code": "no_path_found",
                      "error": "Bad Request",
                      "message": "No swap path found for this asset pair and amount",
                      "path": "/v1/swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "asset_unsupported": {
                    "summary": "asset_unsupported: NEAR Intents cannot swap this asset on the named chain",
                    "value": {
                      "statusCode": 400,
                      "code": "asset_unsupported",
                      "error": "Bad Request",
                      "message": "NEAR Intents does not support asset \"yXLM\" on stellar. GET /v1/cross-chain-swaps/assets lists the ones it does.",
                      "path": "/v1/cross-chain-swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: Cross-chain swaps settle on mainnet only; a dev key cannot open one",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "Cross-chain swaps run on mainnet only: NEAR Intents has no test network. Use a prod API key.",
                      "path": "/v1/cross-chain-swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The payment provider rejected the request.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "merchant_fee_unsupported": {
                    "summary": "merchant_fee_unsupported: This operation cannot pay a merchant fee yet",
                    "value": {
                      "statusCode": 400,
                      "code": "merchant_fee_unsupported",
                      "error": "Bad Request",
                      "message": "A merchant fee is not available on monad swaps on this deployment: Kuru Flow takes one referrer fee per swap and the plan commission uses it, and no merchant fee router is configured (KURU_MERCHANT_FEE_ROUTER).",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "description": "`misconfigured`: the plan charges a commission and the chain has no fee wallet configured (STELLAR_SWAP_FEE_WALLET, SOLANA_SWAP_FEE_WALLET, MONAD_SWAP_FEE_WALLET), or KURU_MERCHANT_FEE_ROUTER is not a MerchantFeeSwapRouter.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "Could not reach the payment provider.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "BlindPay (prod) is not configured: set BLINDPAY_INSTANCE_ID_PROD.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Quote a swap on one chain; persists nothing",
        "tags": [
          "swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "swaps:quote",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "Horizon",
          "Jupiter",
          "Kuru Flow",
          "Solana",
          "Monad"
        ]
      }
    },
    "/v1/swaps": {
      "post": {
        "description": "Prices the swap as the quote does, builds the transaction `source` signs, stores it as `PENDING` and emits `SWAP_CREATED`. Stellar: the XDR with a SEP-7 `uri` and QR, valid for the network timeout (300 s by default); when the swap pays `source` itself (no `destination`, or the same account) and it does not trust the bought asset yet, the transaction adds that trustline first. Solana and Monad (mainnet only): the aggregator’s transaction, valid for one minute on Solana and two on Monad, where an ERC-20 sale may also carry an `approval` to send first. Send the signed transaction to `POST /v1/swaps/{id}/submit`; an `Idempotency-Key` (header or body) makes a retry return the same swap.\n\nRequires the `swaps:write` scope. The shared public key may call it.",
        "operationId": "SwapsController_create_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional idempotency key. A retry with the same key and the same request returns the existing swap (same id and txHash); the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "swap-retry-2026-08-23-001"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateSwapDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "A Stellar swap (no `chain`, or `stellar`), or a Solana / Monad swap. With the shared public key it carries `publicToken`: send it as `X-Record-Token` to read the swap or submit it.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SwapCreatedEntity"
                    },
                    {
                      "$ref": "#/components/schemas/ChainSwapCreatedEntity"
                    }
                  ]
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "Stellar: `trustline_missing` (the destination is another account that does not trust the bought asset, and only it can add the trustline; a source that receives the swap gets the trustline in the same transaction instead), `insufficient_balance` (the source cannot keep the 0.5 XLM reserve that trustline locks, after what the transaction sends and its fee), `no_path_found`. Solana / Monad: `network_unsupported` (a dev key), `asset_unsupported`, `provider_error` (no route, or the aggregator simulated a failure, usually a wallet that cannot cover the amount plus fees). Monad: `merchant_fee_unsupported` (a `merchantFee` and no merchant fee router configured, KURU_MERCHANT_FEE_ROUTER).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "slippage_exceeded": {
                    "summary": "slippage_exceeded: The requested slippage is above what this service allows",
                    "value": {
                      "statusCode": 400,
                      "code": "slippage_exceeded",
                      "error": "Bad Request",
                      "message": "slippageBps 900 exceeds the maximum allowed (500)",
                      "path": "/v1/swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "no_path_found": {
                    "summary": "no_path_found: Horizon found no payment path for this pair and amount",
                    "value": {
                      "statusCode": 400,
                      "code": "no_path_found",
                      "error": "Bad Request",
                      "message": "No swap path found for this asset pair and amount",
                      "path": "/v1/swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, so it cannot receive the swap. Only that account can add the trustline, by signing a transaction of its own: ask its owner to add it, then try again.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "insufficient_balance": {
                    "summary": "insufficient_balance: The source account cannot cover the amount, or the XLM reserve the transaction needs",
                    "value": {
                      "statusCode": 400,
                      "code": "insufficient_balance",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ holds only 12.5000000 shares of this pool",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "asset_unsupported": {
                    "summary": "asset_unsupported: NEAR Intents cannot swap this asset on the named chain",
                    "value": {
                      "statusCode": 400,
                      "code": "asset_unsupported",
                      "error": "Bad Request",
                      "message": "NEAR Intents does not support asset \"yXLM\" on stellar. GET /v1/cross-chain-swaps/assets lists the ones it does.",
                      "path": "/v1/cross-chain-swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: Cross-chain swaps settle on mainnet only; a dev key cannot open one",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "Cross-chain swaps run on mainnet only: NEAR Intents has no test network. Use a prod API key.",
                      "path": "/v1/cross-chain-swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The payment provider rejected the request.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "merchant_fee_unsupported": {
                    "summary": "merchant_fee_unsupported: This operation cannot pay a merchant fee yet",
                    "value": {
                      "statusCode": 400,
                      "code": "merchant_fee_unsupported",
                      "error": "Bad Request",
                      "message": "A merchant fee is not available on monad swaps on this deployment: Kuru Flow takes one referrer fee per swap and the plan commission uses it, and no merchant fee router is configured (KURU_MERCHANT_FEE_ROUTER).",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`idempotency_conflict`: this Idempotency-Key was already used for a different request, or an identical swap was already built without a key (retry with an Idempotency-Key, or wait for the prior swap to settle or expire). `operation_in_flight`: STELLAR_SWAP_SINGLE_INFLIGHT is on and this source account already has a PENDING swap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A withdrawal from this pool is already in flight for this account. Wait for it to settle or expire before starting another: the commission on a withdrawal depends on the position it leaves behind.",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "description": "`misconfigured`: the plan charges a commission and the chain has no fee wallet (or, on Solana, the fee wallet has no token account for the output mint yet), or, for a Monad swap with a merchant fee, KURU_MERCHANT_FEE_ROUTER is not a MerchantFeeSwapRouter or Kuru Flow routes through another aggregator than the one it was deployed for.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "Could not reach the payment provider.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "BlindPay (prod) is not configured: set BLINDPAY_INSTANCE_ID_PROD.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a swap: the unsigned transaction to sign",
        "tags": [
          "swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "swaps:create",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "Horizon",
          "Jupiter",
          "Kuru Flow",
          "Solana",
          "Monad"
        ]
      },
      "get": {
        "description": "Stellar swaps when `chain` is omitted, otherwise those of the chain named, newest first and optionally filtered by `status`. Paginated with `take` (default 20, max 100) and `skip`; the answer is `{ data, total, take, skip }`. Only swaps on the key's network are listed (a `prod` key sees mainnet, a `dev` key testnet), and Solana and Monad swaps are mainnet only, so a `dev` key lists none of them.\n\nRequires the `swaps:read` scope.",
        "operationId": "SwapsController_findAll_v1",
        "parameters": [
          {
            "name": "chain",
            "required": false,
            "in": "query",
            "description": "Which chain to list. Omitted means Stellar.",
            "schema": {
              "default": "stellar",
              "type": "string",
              "enum": [
                "stellar",
                "solana",
                "monad"
              ]
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only swaps in this status.",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "SUBMITTED",
                "SUCCEEDED",
                "FAILED",
                "EXPIRED"
              ]
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "How many swaps to return per page (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many swaps to skip before this page, for pagination.",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Stellar swaps (no `chain`), or those of the chain named.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SwapListEntity"
                    },
                    {
                      "$ref": "#/components/schemas/ChainSwapListEntity"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's swaps on one chain",
        "tags": [
          "swaps"
        ],
        "x-cosmos-scopes": [
          "swaps:read"
        ]
      }
    },
    "/v1/swaps/{id}": {
      "get": {
        "description": "The shared public key may call it, so a swap made without an account can follow its own status, but only with the swap’s `publicToken` in `X-Record-Token`: without it, or with another swap’s, the answer is 404. Every other key reads its own swaps as before. Listing swaps stays closed to the public key.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "SwapsController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Record-Token",
            "in": "header",
            "description": "Required with the shared public key: the `publicToken` the create response returned for this record. Without it, or with the token of another record, the answer is 404, as for a record that does not exist. Ignored for every other API key.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SwapEntity"
                    },
                    {
                      "$ref": "#/components/schemas/ChainSwapEntity"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a swap by id, on any chain",
        "tags": [
          "swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "swaps:read"
        ]
      }
    },
    "/v1/swaps/{id}/submit": {
      "post": {
        "description": "`signedXdr` (Stellar) or `signedTransaction` (Solana, Monad) must be the transaction built for this swap and carry its source's signature, checked before anything about the swap is answered. Stellar: broadcast through Horizon, the answer is `SUCCEEDED` or `submitted: false` with the result codes (a `FAILED` swap can be resubmitted up to 3 times while its envelope is valid). Solana and Monad: broadcast through this service's RPC, the swap is `SUBMITTED` until the observer sees it settle. Emits `SWAP_SUBMITTED`, then `SWAP_SUCCEEDED` or `SWAP_FAILED`; with the shared public key, send the swap's `publicToken` in `X-Record-Token`.\n\nRequires the `swaps:write` scope. The shared public key may call it.",
        "operationId": "SwapsController_submit_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Record-Token",
            "in": "header",
            "description": "With the shared public key, send the `publicToken` the create response returned for this record. A wrong token is 404, as for a record that does not exist. A missing one is still accepted for now (and logged as deprecated) so wallets that do not send it yet keep working; it becomes required here when the deployment sets `PUBLIC_RECORD_TOKEN_REQUIRED_ON_LEGACY=true`. Ignored for every other API key.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitSwapDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SwapSubmitResultEntity"
                    },
                    {
                      "$ref": "#/components/schemas/ChainSwapSubmitResultEntity"
                    }
                  ]
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: `signedXdr` (Stellar) / `signedTransaction` (Solana, Monad) is not a transaction, is not the one built for this swap, or carries no signature of its source. `transaction_rejected`: the Solana or Monad node refused the broadcast; the swap stays PENDING. `invalid_state_transition`: the swap can no longer be submitted, because it is EXPIRED, its transaction's validity window has passed, or it was already resubmitted the maximum number of times after a rejection. Build a new swap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "txHash cannot be changed on a SUCCEEDED payment intent: the status is terminal",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "transaction_rejected": {
                    "summary": "transaction_rejected: The submitted transaction does not do what the route needs",
                    "value": {
                      "statusCode": 400,
                      "code": "transaction_rejected",
                      "error": "Bad Request",
                      "message": "The transaction does not settle this payment intent: the amount paid is below the amount requested",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2/validate",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Rate limited (`rate_limited`), per consumer and client address. Honour `Retry-After`: the window is shorter than the envelope lifetime, so a retry after it still lands in time.",
            "headers": {
              "retry-after": {
                "description": "Seconds to wait before retrying. The only one a browser or a naive retry loop honours: prefer it.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              },
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited: This route’s budget for this caller is spent",
                    "value": {
                      "statusCode": 429,
                      "code": "rate_limited",
                      "error": "Too Many Requests",
                      "message": "Too many requests. Retry in 42s.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Relay the signed swap transaction to its network (checked against the one built); finalizes status",
        "tags": [
          "swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "swaps:submit",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "Horizon",
          "Solana",
          "Monad"
        ]
      }
    },
    "/v1/cross-chain-swaps/assets": {
      "get": {
        "description": "Only what NEAR Intents still trades. A token it tags deprecated is left out, and so is one it lists with no price, because it answers no quote for such a token.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "CrossChainSwapsController_assets_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CrossChainAssetListEntity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "List the assets NEAR Intents can swap, with an indicative USD price",
        "tags": [
          "cross-chain-swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "NEAR Intents"
        ]
      }
    },
    "/v1/cross-chain-swaps/quote": {
      "post": {
        "description": "A dry NEAR Intents quote for `amount` of `originAsset` on `originChain` into `destinationAsset` on `destinationChain`: the expected and minimum output, the plan commission (`fee`, in the origin asset), any `merchantFee` (its wallet a NEAR account) and a time estimate. Prices are mainnet's for every key, a `dev` key included. A pair on one chain among Stellar, Solana and Monad is `validation_failed`: those go through `POST /v1/swaps`. `slippageBps` defaults to 100 and is capped at 500, unless the deployment configures other values.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "CrossChainSwapsController_quote_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteCrossChainSwapDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CrossChainQuoteEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`provider_error`: NEAR Intents refused the quote (an amount below its minimum, a route it cannot fill); `message` carries its reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "slippage_exceeded": {
                    "summary": "slippage_exceeded: The requested slippage is above what this service allows",
                    "value": {
                      "statusCode": 400,
                      "code": "slippage_exceeded",
                      "error": "Bad Request",
                      "message": "slippageBps 900 exceeds the maximum allowed (500)",
                      "path": "/v1/swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "asset_unsupported": {
                    "summary": "asset_unsupported: NEAR Intents cannot swap this asset on the named chain",
                    "value": {
                      "statusCode": 400,
                      "code": "asset_unsupported",
                      "error": "Bad Request",
                      "message": "NEAR Intents does not support asset \"yXLM\" on stellar. GET /v1/cross-chain-swaps/assets lists the ones it does.",
                      "path": "/v1/cross-chain-swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The payment provider rejected the request.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "description": "`provider_unavailable`: NEAR Intents is down or rate limiting this service; retry. `misconfigured`: the plan charges a commission and NEAR_INTENTS_FEE_RECIPIENT is not set, or NEAR Intents rejected NEAR_INTENTS_API_KEY.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "Could not reach the payment provider.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "BlindPay (prod) is not configured: set BLINDPAY_INSTANCE_ID_PROD.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Quote a cross-chain swap through NEAR Intents (price, commission, minimum); persists nothing",
        "tags": [
          "cross-chain-swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "cross-chain-swaps:quote",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "NEAR Intents"
        ]
      }
    },
    "/v1/cross-chain-swaps": {
      "post": {
        "description": "Asks NEAR Intents for a live quote with a deposit address for this swap alone, stores it as `AWAITING_DEPOSIT` and emits `CROSS_CHAIN_SWAP_CREATED`. The payer sends `amountIn` to `depositAddress` (with `depositMemo` when set) before `expiresAt`; `depositUri` is a wallet link in the origin chain's standard (SEP-7, Solana Pay, EIP-681, BIP-21, TON, CIP-13) with a QR, or null where the chain has none. NEAR Intents pays `recipient` or refunds `refundTo`, and a Stellar `recipient` must already trust the asset. Mainnet only; an `Idempotency-Key` (header or body) makes a retry return the same swap and address.\n\nRequires the `swaps:write` scope. The shared public key may call it.",
        "operationId": "CrossChainSwapsController_create_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional idempotency key. A retry with the same key and the same request returns the existing swap (same deposit address); the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "xswap-retry-2026-10-02-001"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCrossChainSwapDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The swap. With the shared public key it carries `publicToken`: send it as `X-Record-Token` to read the swap or report its deposit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CrossChainSwapCreatedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`network_unsupported`: a dev (testnet) key, and NEAR Intents settles on mainnet only. `trustline_missing`: a Stellar recipient does not trust the destination asset, and only that account can add the trustline. `provider_error`: NEAR Intents refused the quote.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "slippage_exceeded": {
                    "summary": "slippage_exceeded: The requested slippage is above what this service allows",
                    "value": {
                      "statusCode": 400,
                      "code": "slippage_exceeded",
                      "error": "Bad Request",
                      "message": "slippageBps 900 exceeds the maximum allowed (500)",
                      "path": "/v1/swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "asset_unsupported": {
                    "summary": "asset_unsupported: NEAR Intents cannot swap this asset on the named chain",
                    "value": {
                      "statusCode": 400,
                      "code": "asset_unsupported",
                      "error": "Bad Request",
                      "message": "NEAR Intents does not support asset \"yXLM\" on stellar. GET /v1/cross-chain-swaps/assets lists the ones it does.",
                      "path": "/v1/cross-chain-swaps/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: Cross-chain swaps settle on mainnet only; a dev key cannot open one",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "Cross-chain swaps run on mainnet only: NEAR Intents has no test network. Use a prod API key.",
                      "path": "/v1/cross-chain-swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, so it cannot receive the swap. Only that account can add the trustline, by signing a transaction of its own: ask its owner to add it, then try again.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The payment provider rejected the request.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "This Idempotency-Key was already used for a different cross-chain swap request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "description": "`provider_unavailable`: NEAR Intents is down or rate limiting this service; retry. `misconfigured`: the plan charges a commission and NEAR_INTENTS_FEE_RECIPIENT is not set, or NEAR Intents rejected NEAR_INTENTS_API_KEY.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "Could not reach the payment provider.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "BlindPay (prod) is not configured: set BLINDPAY_INSTANCE_ID_PROD.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a cross-chain swap: a NEAR Intents deposit address to pay",
        "tags": [
          "cross-chain-swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "cross-chain-swaps:create",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "NEAR Intents",
          "Horizon"
        ]
      },
      "get": {
        "description": "Answered from this service's own table, which the observer keeps current from NEAR Intents: newest first, optionally filtered by `status`. Paginated with `take` (default 20, max 100) and `skip`; the answer is `{ data, total, take, skip }`. Cross-chain swaps run on mainnet only, so a `dev` key lists none.\n\nRequires the `swaps:read` scope.",
        "operationId": "CrossChainSwapsController_findAll_v1",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only cross-chain swaps in this status.",
            "schema": {
              "type": "string",
              "enum": [
                "AWAITING_DEPOSIT",
                "DEPOSIT_DETECTED",
                "INCOMPLETE_DEPOSIT",
                "PROCESSING",
                "SUCCEEDED",
                "REFUNDED",
                "FAILED",
                "EXPIRED"
              ]
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "How many swaps to return per page (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many swaps to skip before this page, for pagination.",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CrossChainSwapListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's cross-chain swaps",
        "tags": [
          "cross-chain-swaps"
        ],
        "x-cosmos-scopes": [
          "swaps:read"
        ]
      }
    },
    "/v1/cross-chain-swaps/{id}": {
      "get": {
        "description": "The shared public key may call it, so a swap made without an account can follow its own status, but only with the swap’s `publicToken` in `X-Record-Token`: without it, or with another swap’s, the answer is 404. Every other key reads its own swaps as before. Listing swaps stays closed to the public key.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "CrossChainSwapsController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Record-Token",
            "in": "header",
            "description": "Required with the shared public key: the `publicToken` the create response returned for this record. Without it, or with the token of another record, the answer is 404, as for a record that does not exist. Ignored for every other API key.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CrossChainSwapEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a cross-chain swap by id",
        "tags": [
          "cross-chain-swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "swaps:read"
        ]
      }
    },
    "/v1/cross-chain-swaps/{id}/deposit": {
      "post": {
        "description": "`txHash` must have the shape of a transaction id on the origin chain; NEAR Intents then reads that chain itself and credits only what really arrived at `depositAddress`. The swap records `depositTxHash`, moves to the status NEAR Intents reports and emits the matching `CROSS_CHAIN_SWAP_*` event when that status changes. Reporting is optional, since the observer follows the swap either way; with the shared public key, send the swap's `publicToken` in `X-Record-Token`.\n\nRequires the `swaps:write` scope. The shared public key may call it.",
        "operationId": "CrossChainSwapsController_submitDeposit_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Record-Token",
            "in": "header",
            "description": "With the shared public key, send the `publicToken` the create response returned for this record. A wrong token is 404, as for a record that does not exist. A missing one is still accepted for now (and logged as deprecated) so wallets that do not send it yet keep working; it becomes required here when the deployment sets `PUBLIC_RECORD_TOKEN_REQUIRED_ON_LEGACY=true`. Ignored for every other API key.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitDepositDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CrossChainSwapEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: txHash is not a transaction id of the origin chain. `invalid_state_transition`: the swap already SUCCEEDED, was REFUNDED or FAILED. `provider_error`: NEAR Intents refused the hash.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "txHash cannot be changed on a SUCCEEDED payment intent: the status is terminal",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The payment provider rejected the request.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Report the deposit transaction to NEAR Intents so the swap starts without waiting for its indexer",
        "tags": [
          "cross-chain-swaps"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "cross-chain-swaps:deposit",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "NEAR Intents"
        ]
      }
    },
    "/v1/liquidity-pools/deposit": {
      "post": {
        "description": "Builds a `liquidityPoolDeposit` on the key's network for `source` to sign (preceded by the pool-share trustline when the account has none), stores it as `PENDING` and emits `LIQUIDITY_CREATED`. Leave `maxAmountB` out to match the pool’s current ratio (an empty pool needs both amounts, which set its price); the price bounds bracket the pool price by `slippageBps` (default 50, cap 500 unless configured). Deposits pay no plan commission; a `merchantFee` is paid from each asset, and `source` must trust both assets and afford the amounts plus its reserve (`trustline_missing`, `insufficient_balance`). An `Idempotency-Key` (header or body) makes a retry return the same operation.\n\nRequires the `liquidity:write` or `swaps:write` scope. The shared public key may call it.",
        "operationId": "LiquidityPoolsController_deposit_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional idempotency key. A retry with the same key and the same request returns the existing operation (same id and txHash); the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "lp-deposit-2026-08-23-001"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DepositLiquidityDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquidityOperationEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`invalid_amount`: Not a Stellar amount, or not greater than zero\n\n`trustline_missing`: An account does not trust the asset, and this request cannot add the trustline for it\n\n`insufficient_balance`: The source account cannot cover the amount, or the XLM reserve the transaction needs",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, so it cannot receive the swap. Only that account can add the trustline, by signing a transaction of its own: ask its owner to add it, then try again.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "insufficient_balance": {
                    "summary": "insufficient_balance: The source account cannot cover the amount, or the XLM reserve the transaction needs",
                    "value": {
                      "statusCode": 400,
                      "code": "insufficient_balance",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ holds only 12.5000000 shares of this pool",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`idempotency_conflict`: this Idempotency-Key was already used for a different request, or an identical deposit was already built without a key (retry with an Idempotency-Key, or wait for the prior operation to settle or expire).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Build a pool deposit → unsigned XDR + SEP-7 tx URI + QR for the wallet to sign",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "liquidity-pools:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes-any": [
          "liquidity:write",
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/liquidity-pools/withdraw": {
      "post": {
        "description": "Builds a `liquidityPoolWithdraw` of `shares` from `poolId` on the key's network for `source` to sign, with minimum amounts of each reserve set from the current reserves less `slippageBps`, stores it as `PENDING` and emits `LIQUIDITY_CREATED`. The plan commission is charged only on the gain over the cost basis of shares deposited through this service, out of the withdrawn reserves; a `merchantFee` is a share of the minimum amounts. A withdrawal from the same pool that may already be on-chain blocks another one for that account (`operation_in_flight`); an `Idempotency-Key` (header or body) makes a retry return the same operation.\n\nRequires the `liquidity:write` or `swaps:write` scope. The shared public key may call it.",
        "operationId": "LiquidityPoolsController_withdraw_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional idempotency key. A retry with the same key and the same request returns the existing operation (same id and txHash); the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "lp-withdraw-2026-08-23-001"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WithdrawLiquidityDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquidityOperationEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`invalid_amount`: Not a Stellar amount, or not greater than zero\n\n`insufficient_balance`: The source account cannot cover the amount, or the XLM reserve the transaction needs\n\n`trustline_missing`: An account does not trust the asset, and this request cannot add the trustline for it",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "Deposit amounts must be greater than zero",
                      "path": "/v1/liquidity-pools/deposit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "insufficient_balance": {
                    "summary": "insufficient_balance: The source account cannot cover the amount, or the XLM reserve the transaction needs",
                    "value": {
                      "statusCode": 400,
                      "code": "insufficient_balance",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ holds only 12.5000000 shares of this pool",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, so it cannot receive the swap. Only that account can add the trustline, by signing a transaction of its own: ask its owner to add it, then try again.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`idempotency_conflict`: this Idempotency-Key was already used for a different request, or an identical withdrawal was already built without a key. `operation_in_flight`: a withdrawal from this pool is already in flight for this account; wait for it to settle or expire.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A swap already exists for this Idempotency-Key",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A withdrawal from this pool is already in flight for this account. Wait for it to settle or expire before starting another: the commission on a withdrawal depends on the position it leaves behind.",
                      "path": "/v1/liquidity-pools/withdraw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Build a pool withdrawal (burn shares) → unsigned XDR + SEP-7 tx URI + QR",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "liquidity-pools:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes-any": [
          "liquidity:write",
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/liquidity-pools/positions": {
      "get": {
        "description": "Reads `account`'s pool-share trustlines from Horizon on the key's network and, per pool, its shares, its share of the pool in basis points, the reserves and what those shares redeem now. Ledger data, not this consumer's rows: any account can be read, and nothing is stored.\n\nRequires the `liquidity:read` or `swaps:read` scope. The shared public key may call it.",
        "operationId": "LiquidityPoolsController_positions_v1",
        "parameters": [
          {
            "name": "account",
            "required": true,
            "in": "query",
            "description": "Account whose pool share trustlines to inspect.",
            "schema": {
              "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquidityPositionListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "An account's pool share positions with redeemable amounts",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/liquidity-pools/operations": {
      "get": {
        "description": "The deposits and withdrawals built through this service, newest first, optionally filtered by `kind` and `status`. Paginated with `take` (default 20, max 100) and `skip`; the answer is `{ data, total, take, skip }`. Only operations on the key's network are listed (a `prod` key sees mainnet, a `dev` key testnet).\n\nRequires the `liquidity:read` or `swaps:read` scope.",
        "operationId": "LiquidityPoolsController_findAllOperations_v1",
        "parameters": [
          {
            "name": "kind",
            "required": false,
            "in": "query",
            "description": "Only operations of this kind (`DEPOSIT` or `WITHDRAW`).",
            "schema": {
              "type": "string",
              "enum": [
                "DEPOSIT",
                "WITHDRAW"
              ]
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only operations in this status.",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "SUBMITTED",
                "SUCCEEDED",
                "FAILED",
                "EXPIRED"
              ]
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "How many operations to return per page (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many matching operations to skip before the page starts (newest first).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquidityOperationListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's liquidity pool operations",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ]
      }
    },
    "/v1/liquidity-pools/operations/{id}": {
      "get": {
        "description": "One deposit or withdrawal this consumer built: its unsigned XDR, SEP-7 `uri` and QR, its status, and the commission and merchant fee it carries. Answered from this service's own table, which submit and the settlement observer keep current.\n\nRequires the `liquidity:read` or `swaps:read` scope.",
        "operationId": "LiquidityPoolsController_findOneOperation_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquidityOperationEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a liquidity pool operation by id",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ]
      }
    },
    "/v1/liquidity-pools/operations/{id}/submit": {
      "post": {
        "description": "`signedXdr` must hash to the operation's stored transaction and carry a signature, checked before anything about the operation is answered. It is broadcast through Horizon and the answer is `SUCCEEDED` or `submitted: false` with the result codes (a `FAILED` operation can be resubmitted up to 3 times while its envelope is valid); an unreachable Horizon is a 503 that leaves it resubmittable. Emits `LIQUIDITY_SUBMITTED`, then `LIQUIDITY_SUCCEEDED` or `LIQUIDITY_FAILED`, and a settled deposit records the cost basis the withdrawal commission is charged against.\n\nRequires the `liquidity:write` or `swaps:write` scope. The shared public key may call it.",
        "operationId": "LiquidityPoolsController_submit_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitLiquidityDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquiditySubmitResultEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: `signedXdr` is not a transaction envelope, is not the envelope built for this operation, or carries no signatures. `invalid_state_transition`: the operation can no longer be submitted, because it is EXPIRED, its transaction's time bounds have passed, or it was already resubmitted the maximum number of times after a rejection. Build a new deposit or withdrawal.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "txHash cannot be changed on a SUCCEEDED payment intent: the status is terminal",
                      "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "description": "Rate limited (`rate_limited`), per consumer and client address, in a bucket separate from the swaps submit route. Honour `Retry-After`: the window is shorter than the envelope lifetime, so a retry after it still lands in time.",
            "headers": {
              "retry-after": {
                "description": "Seconds to wait before retrying. The only one a browser or a naive retry loop honours: prefer it.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              },
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "rate_limited": {
                    "summary": "rate_limited: This route’s budget for this caller is spent",
                    "value": {
                      "statusCode": 429,
                      "code": "rate_limited",
                      "error": "Too Many Requests",
                      "message": "Too many requests. Retry in 42s.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Relay the signed transaction to the network (hash-checked); finalizes status",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "liquidity:submit",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes-any": [
          "liquidity:write",
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/liquidity-pools": {
      "get": {
        "description": "Horizon's pool list on the key's network, in descending order, optionally narrowed to pools holding one or two assets (`assetACode`/`assetAIssuer`, `assetBCode`/`assetBIssuer`) or to those an `account` holds shares in. Paged by Horizon cursor, not `take`/`skip`: `limit` per page (default 20, max 100), and the answer's `cursor` fetches the next page (null when the page is not full). Nothing is stored.\n\nRequires the `liquidity:read` or `swaps:read` scope. The shared public key may call it.",
        "operationId": "LiquidityPoolsController_listPools_v1",
        "parameters": [
          {
            "name": "assetACode",
            "required": false,
            "in": "query",
            "description": "Filter to pools containing this asset. Pass \"XLM\"/\"native\" for lumens.",
            "schema": {
              "example": "USDC",
              "type": "string"
            }
          },
          {
            "name": "assetAIssuer",
            "required": false,
            "in": "query",
            "description": "Issuer for a non-native first asset.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "assetBCode",
            "required": false,
            "in": "query",
            "description": "Second asset of the pair (narrows to the exact pool).",
            "schema": {
              "example": "XLM",
              "type": "string"
            }
          },
          {
            "name": "assetBIssuer",
            "required": false,
            "in": "query",
            "description": "Issuer for a non-native second asset.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "account",
            "required": false,
            "in": "query",
            "description": "Only pools this account participates in.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "cursor",
            "required": false,
            "in": "query",
            "description": "Horizon paging cursor.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "required": false,
            "in": "query",
            "description": "How many pools to return per page (1 to 100). Page on with the `cursor` the answer returns.",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquidityPoolListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Browse on-chain liquidity pools (Horizon proxy)",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/liquidity-pools/{poolId}": {
      "get": {
        "description": "One pool read from Horizon on the key's network: its fee, trustline count, total shares and reserves. `poolId` is the 64-character lowercase hex pool id; any other shape is `validation_failed`, and a pool that does not exist on that network is a 404.\n\nRequires the `liquidity:read` or `swaps:read` scope. The shared public key may call it.",
        "operationId": "LiquidityPoolsController_getPool_v1",
        "parameters": [
          {
            "name": "poolId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LiquidityPoolEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Get a liquidity pool by id (Horizon proxy)",
        "tags": [
          "liquidity-pools"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/assets": {
      "get": {
        "description": "The wallet ships a bundled copy of this list and prefers whichever of the two carries the higher `version`, so a client that cannot reach this endpoint still resolves assets correctly. It just misses the newest additions.\n\nRequires an API key, with no particular scope. The shared public key may call it.",
        "operationId": "AssetsController_list_v1",
        "parameters": [
          {
            "name": "network",
            "required": false,
            "in": "query",
            "description": "Which Stellar network to list.",
            "schema": {
              "default": "public",
              "type": "string",
              "enum": [
                "public",
                "testnet"
              ]
            }
          },
          {
            "name": "verified",
            "required": false,
            "in": "query",
            "description": "Return only issuer-verified entries. Omit to get the whole catalog, verified and not, and render the difference.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AssetListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Known Stellar assets per network, with issuer identity",
        "tags": [
          "assets"
        ],
        "x-cosmos-public-key": true
      }
    },
    "/v1/public-key": {
      "get": {
        "description": "Public: no API key, since a wallet without an account holds none yet. `env=dev` (the default) returns the testnet key and `env=prod` the mainnet one; that key reaches only the routes marked `x-cosmos-public-key`. Cached for 5 minutes (`Cache-Control: public, max-age=300`) so a rotation reaches wallets quickly; `503 misconfigured` when this deployment publishes no key for that environment.",
        "operationId": "PublicKeyController_get_v1",
        "parameters": [
          {
            "name": "env",
            "required": false,
            "in": "query",
            "description": "`dev` is the testnet key, `prod` the public-network one.",
            "schema": {
              "default": "dev",
              "type": "string",
              "enum": [
                "dev",
                "prod"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicKeyEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "`misconfigured`: A server-side configuration error: retrying will not help",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "No public key is published for the prod environment: set PUBLIC_API_KEY_PROD.",
                      "path": "/v1/public-key",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "The shared public API key for an environment",
        "tags": [
          "public-key"
        ],
        "x-cosmos-public": true,
        "security": []
      }
    },
    "/v1/webhooks": {
      "post": {
        "description": "`url` must be `https`, carry no credentials and resolve to a public address (loopback, private, link-local and cloud metadata hosts are `400 validation_failed`). `secret` (`whsec_...`) is returned only here and on rotation: every delivery is signed with it in the signature header (`x-cosmos-signature` by default) as `t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<body>\">`. An empty or omitted `eventTypes` receives every event type.\n\nRequires the `webhooks:write` scope.",
        "operationId": "WebhooksController_create_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWebhookEndpointDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointWithSecretEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Register a webhook endpoint (returns the signing secret, shown once)",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-scopes": [
          "webhooks:write"
        ]
      },
      "get": {
        "description": "Newest first, as `{ data, total, take, skip }` with `take` up to 100 (default 100), without signing secrets. `destinationBlocked` marks an endpoint this service disabled because its host stopped resolving to a public address.\n\nRequires the `webhooks:read` scope.",
        "operationId": "WebhooksController_findAll_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's webhook endpoints",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-scopes": [
          "webhooks:read"
        ]
      }
    },
    "/v1/webhooks/{id}": {
      "get": {
        "description": "The endpoint without its signing secret, which only the create and rotate-secret routes return.\n\nRequires the `webhooks:read` scope.",
        "operationId": "WebhooksController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a webhook endpoint",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-scopes": [
          "webhooks:read"
        ]
      },
      "patch": {
        "description": "Changes only the fields sent. A new `url` is checked as on create, `enabled: true` checks the stored one again, and either clears `destinationBlocked`. `eventTypes` replaces the filter (an empty list receives every event type).\n\nRequires the `webhooks:write` scope.",
        "operationId": "WebhooksController_update_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateWebhookEndpointDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Update a webhook endpoint (url/description/enabled/eventTypes)",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-scopes": [
          "webhooks:write"
        ]
      },
      "delete": {
        "description": "Deletes the endpoint together with its delivery history; nothing more is sent to it.\n\nRequires the `webhooks:write` scope.",
        "operationId": "WebhooksController_remove_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Delete a webhook endpoint",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-scopes": [
          "webhooks:write"
        ]
      }
    },
    "/v1/webhooks/{id}/rotate-secret": {
      "post": {
        "description": "Replaces `secret` at once and returns the new one, shown only here. Every delivery sent from now on is signed with the new secret only: the old one has no grace period.\n\nRequires the `webhooks:write` scope.",
        "operationId": "WebhooksController_rotateSecret_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEndpointWithSecretEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Rotate the signing secret (returns the new secret)",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-scopes": [
          "webhooks:write"
        ]
      }
    },
    "/v1/webhooks/{id}/ping": {
      "post": {
        "description": "POSTs one signed `ping` event (not stored as a delivery) to the endpoint, enabled or not, and answers whether it replied 2xx (`ok`, `responseStatus`, `error`). A URL that no longer resolves to a public address disables the endpoint and marks it `destinationBlocked`.\n\nRequires the `webhooks:write` scope.",
        "operationId": "WebhooksController_ping_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookPingEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Send a test event to verify the endpoint",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "webhooks:ping",
            "limit": 20,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "webhooks:write"
        ]
      }
    },
    "/v1/webhooks/{id}/deliveries": {
      "get": {
        "description": "Newest first, as `{ data, total, take, skip }` with `take` up to 100 (default 20), narrowed by `status` when given. Each delivery reports its `eventType`, `eventId`, `attempts`, last `responseStatus` and `error`; the event body that was sent is never returned.\n\nRequires the `webhooks:read` scope.",
        "operationId": "WebhooksController_listDeliveries_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only deliveries in this status. Omit for every status.",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "SUCCEEDED",
                "FAILED",
                "RETRYING"
              ]
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List delivery attempts for an endpoint (audit trail)",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-scopes": [
          "webhooks:read"
        ]
      }
    },
    "/v1/webhooks/{id}/deliveries/{deliveryId}/redeliver": {
      "post": {
        "description": "Re-sends the stored body with the same event id, signed again with the endpoint's current secret, retrying with backoff inside this request until a 2xx or the attempts run out, and answers the updated delivery (without its body). A delivery past its payload retention window is `409 payload_expired`.\n\nRequires the `webhooks:write` scope.",
        "operationId": "WebhooksController_redeliver_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "deliveryId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`payload_expired`: the delivery is past its retention window. The event body was cleared, so there is nothing left to re-send; the delivery row itself stays as an audit record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "payload_expired": {
                    "summary": "payload_expired: The delivery body is past retention and cannot be re-sent",
                    "value": {
                      "statusCode": 409,
                      "code": "payload_expired",
                      "error": "Conflict",
                      "message": "Delivery wd_8Rt2Vy6Hn4 is past its retention window: the event body was cleared and can no longer be re-sent.",
                      "path": "/v1/webhooks/we_5Mq0Zb3Jc7/deliveries/wd_8Rt2Vy6Hn4/redeliver",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Manually re-send a past delivery",
        "tags": [
          "webhooks"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "webhooks:redeliver",
            "limit": 30,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "webhooks:write"
        ]
      }
    },
    "/v1/summary": {
      "get": {
        "description": "The settled volume per asset, and every asset valued in USD at NEAR Intents' current reference price (`volumeUsd`, indicative). Without those prices the USD fields are null and the rest answers as usual.\n\nRequires the `payments:read` scope.",
        "operationId": "AnalyticsController_summary_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsSummaryEntity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Overview metrics: totals, settled volume, webhook health, 30-day series",
        "tags": [
          "analytics"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/summary/series": {
      "get": {
        "description": "Payments, swaps, liquidity operations, webhook deliveries and private payments, each grouped into the buckets of `period` (UTC, weeks from Monday, a quiet bucket a zero), with the totals of the window and of the window before, for growth. Payments carry their settled volume in USD too (`volumeUsd`), each asset valued at NEAR Intents' current reference price (indicative). Without those prices the USD fields are null and the rest answers as usual.\n\nRequires the `payments:read` scope.",
        "operationId": "AnalyticsController_series_v1",
        "parameters": [
          {
            "name": "period",
            "required": false,
            "in": "query",
            "description": "day: 30 days, week: 12 weeks, month: 12 months, year: 5 years.",
            "schema": {
              "default": "day",
              "type": "string",
              "enum": [
                "day",
                "week",
                "month",
                "year"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsSeriesEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Activity per day, week, month or year, with the window before",
        "tags": [
          "analytics"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/balances": {
      "get": {
        "description": "Per chain and asset, what this consumer's payment intents settled (`amount`, with their `count`) and what is still `PENDING` or `SUBMITTED` (`pending`), on the API key’s network only (mainnet for a production key, testnet for a test key). Largest settled amount first, as `{ data, total }` with no paging. Reused per consumer and network for a few seconds (10 by default), so a new payment can take that long to show.\n\nRequires the `payments:read` scope.",
        "operationId": "AnalyticsController_balances_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AnalyticsBalancesEntity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Settled (and pending) amount per asset",
        "tags": [
          "analytics"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/logs": {
      "get": {
        "description": "This consumer's requests, newest first, with method, path, status code, duration, client IP and user agent; the dashboard’s own console calls are left out. `status` is `ok` below 400, `pending` for a 4xx and `fail` for a 5xx. Paged with `take` (default and maximum 100) and `skip`; answers `{ data, total, take, skip }`, never cached.\n\nRequires the `payments:read` scope.",
        "operationId": "AnalyticsController_apiLogs_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiLogListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Recent API requests reaching the service (with details)",
        "tags": [
          "analytics"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/logs/webhooks": {
      "get": {
        "description": "Deliveries to every webhook endpoint of this consumer, newest first: the endpoint and its `url`, `eventType`, `eventId`, `attempts`, the last `responseStatus` and `error`, and `status` (`ok` when delivered, `fail` when failed, `pending` otherwise). The payload is never included. Paged with `take` (default and maximum 100) and `skip`; answers `{ data, total, take, skip }`, never cached.\n\nRequires the `webhooks:read` scope.",
        "operationId": "AnalyticsController_webhookLogs_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookLogListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Recent webhook deliveries across all endpoints (with details)",
        "tags": [
          "analytics"
        ],
        "x-cosmos-scopes": [
          "webhooks:read"
        ]
      }
    },
    "/v1/activity/events": {
      "post": {
        "description": "Accepted, not created: the batch is written under the consumer the gateway authenticated, and nothing in the body can change that attribution. Over-long messages are truncated and an over-sized `props` is replaced with a marker rather than failing the call: losing a whole batch to one malformed field is worst exactly when the client is in a state it did not anticipate.\n\nRequires the `activity:write` scope. The shared public key may call it.",
        "operationId": "ActivityController_ingest_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/IngestActivityDto"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Accepted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivityIngestResultEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Report a batch of client events (errors, metrics, transactions)",
        "tags": [
          "activity"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "activity:ingest",
            "limit": 120,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "activity:write"
        ]
      },
      "get": {
        "description": "`level` is a floor, not an exact match: `level=warn` returns warnings and errors.\n\nRequires the `activity:read` scope.",
        "operationId": "ActivityController_list_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Only events reported by this client.",
            "schema": {
              "type": "string",
              "enum": [
                "wallet",
                "dashboard",
                "server",
                "sdk"
              ]
            }
          },
          {
            "name": "level",
            "required": false,
            "in": "query",
            "description": "Minimum severity, not an exact match: `warn` returns warnings and errors.",
            "schema": {
              "type": "string",
              "enum": [
                "debug",
                "info",
                "warn",
                "error"
              ]
            }
          },
          {
            "name": "category",
            "required": false,
            "in": "query",
            "description": "Only events of this category (exact match).",
            "schema": {
              "example": "transaction",
              "type": "string"
            }
          },
          {
            "name": "type",
            "required": false,
            "in": "query",
            "description": "Prefix match on the event name.",
            "schema": {
              "example": "payment.",
              "type": "string"
            }
          },
          {
            "name": "network",
            "required": false,
            "in": "query",
            "description": "Only events reported on this network (exact match).",
            "schema": {
              "example": "testnet",
              "type": "string"
            }
          },
          {
            "name": "since",
            "required": false,
            "in": "query",
            "description": "Only events that occurred at or after this instant.",
            "schema": {
              "example": "2026-09-01T00:00:00.000Z",
              "type": "string"
            }
          },
          {
            "name": "until",
            "required": false,
            "in": "query",
            "description": "Only events that occurred at or before this instant.",
            "schema": {
              "example": "2026-09-07T00:00:00.000Z",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivityEventListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Recent client events for this consumer, newest first",
        "tags": [
          "activity"
        ],
        "x-cosmos-scopes": [
          "activity:read"
        ]
      }
    },
    "/v1/activity/summary": {
      "get": {
        "description": "Rolls up the client events this consumer reported over the last `days` days (default 7, at most 90), optionally for one `source`: the total, distinct sessions and devices, counts per level, source and category, and the 10 most frequent event types and error messages. `series` has one entry per UTC day, zero on a quiet one.\n\nRequires the `activity:read` scope.",
        "operationId": "ActivityController_summary_v1",
        "parameters": [
          {
            "name": "days",
            "required": false,
            "in": "query",
            "description": "Days the rollup covers, today included.",
            "schema": {
              "minimum": 1,
              "maximum": 90,
              "default": 7,
              "type": "number"
            }
          },
          {
            "name": "source",
            "required": false,
            "in": "query",
            "description": "Only events reported by this client.",
            "schema": {
              "type": "string",
              "enum": [
                "wallet",
                "dashboard",
                "server",
                "sdk"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ActivitySummaryEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Counts, top event types, top errors and a daily series",
        "tags": [
          "activity"
        ],
        "x-cosmos-scopes": [
          "activity:read"
        ]
      }
    },
    "/v1/products": {
      "post": {
        "description": "A catalog record: `name`, an optional decimal `amount` (up to 7 decimals; omit for a customer-set price), `assetCode` (omitted, `XLM` or `native` store `native`), `kind` (`one_time` by default, `recurring` or `link`, informational) and `active` (default `true`). Creating one builds no payment link or intent.\n\nRequires the `products:write` scope.",
        "operationId": "ProductsController_create_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProductDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Create a product",
        "tags": [
          "products"
        ],
        "x-cosmos-scopes": [
          "products:write"
        ]
      },
      "get": {
        "description": "Newest first, as `{ data, total, take, skip }` with `take` up to 100 (default 100). Inactive products (`active: false`) are included.\n\nRequires the `products:read` scope.",
        "operationId": "ProductsController_findAll_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's products",
        "tags": [
          "products"
        ],
        "x-cosmos-scopes": [
          "products:read"
        ]
      }
    },
    "/v1/products/{id}": {
      "get": {
        "description": "One of the consumer’s products, active or not.\n\nRequires the `products:read` scope.",
        "operationId": "ProductsController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a product by id",
        "tags": [
          "products"
        ],
        "x-cosmos-scopes": [
          "products:read"
        ]
      },
      "patch": {
        "description": "Changes only the fields sent; `assetCode` is normalized as on create. Set `active: false` to retire a product and keep its record.\n\nRequires the `products:write` scope.",
        "operationId": "ProductsController_update_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProductDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Update a product",
        "tags": [
          "products"
        ],
        "x-cosmos-scopes": [
          "products:write"
        ]
      },
      "delete": {
        "description": "Deletes the product for good. To keep its record, set `active: false` with `PATCH` instead.\n\nRequires the `products:write` scope.",
        "operationId": "ProductsController_remove_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProductDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Delete a product",
        "tags": [
          "products"
        ],
        "x-cosmos-scopes": [
          "products:write"
        ]
      }
    },
    "/v1/aliases/resolve/{name}": {
      "get": {
        "description": "Answers the addresses of the alias on one chain (Stellar unless `chain` names another), optionally narrowed to one `network`, primary first, with `primaryAddress` as the default to pay (null when it has none there). The name is matched trimmed and lowercased. An unknown or suspended alias is a 404, and nothing about its owner is returned.\n\nRequires the `payments:read` scope. The shared public key may call it.",
        "operationId": "AliasesController_resolve_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "network",
            "required": false,
            "in": "query",
            "description": "Limit to one network (public | testnet | a custom id).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "chain",
            "required": false,
            "in": "query",
            "description": "The chain to resolve on. Omit for Stellar: a wallet that does not ask for a chain is never handed another chain’s address.",
            "schema": {
              "enum": [
                "stellar",
                "solana",
                "monad"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasResolutionEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Resolve an alias to its addresses",
        "tags": [
          "aliases"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/aliases/availability/{name}": {
      "get": {
        "description": "Checks the trimmed, lowercased handle and answers `available`, with a `reason` when it is not: `too_short` or `too_long` (3 to 32 characters), `bad_characters` (a-z, 0-9 and underscores, starting and ending with a letter or digit), `reserved`, `address_like` (it would read as a Stellar address) or `taken`. It reserves nothing: a claim can still lose the name with `409 alias_taken`.\n\nRequires the `payments:read` scope. The shared public key may call it.",
        "operationId": "AliasesController_availability_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasAvailabilityEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Is this handle claimable, and if not why not",
        "tags": [
          "aliases"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/aliases/by-address/{address}": {
      "get": {
        "description": "The active aliases holding this address, oldest first, each with its `chain`, `network` and whether the address is its primary there, as `{ data }` (not paged). Without `chain` the chain is read off the address's own shape, and a Monad address matches whatever its letter case. An address no chain accepts answers an empty `data`, not an error.\n\nRequires the `payments:read` scope. The shared public key may call it.",
        "operationId": "AliasesController_byAddress_v1",
        "parameters": [
          {
            "name": "address",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "network",
            "required": false,
            "in": "query",
            "description": "Limit to addresses registered on this network (public | testnet | a custom id). Omit for every network.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "chain",
            "required": false,
            "in": "query",
            "description": "Omit to read the chain off the address’s own shape.",
            "schema": {
              "enum": [
                "stellar",
                "solana",
                "monad"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasByAddressEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Which aliases point at this address",
        "tags": [
          "aliases"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/aliases/challenges": {
      "post": {
        "description": "Returns the EXACT message to digest and sign. Single-use and short-lived; the purpose is inside the signed bytes, so a signature collected to add an address cannot be replayed to complete a recovery.\n\nRequires the `payments:write` scope.",
        "operationId": "AliasesController_challenge_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateAliasChallengeDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasChallengeEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`alias_name_invalid`: Reserved, malformed, or the wrong length",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_name_invalid": {
                    "summary": "alias_name_invalid: Reserved, malformed, or the wrong length",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_name_invalid",
                      "error": "Bad Request",
                      "message": "An alias may use a-z, 0-9 and underscores, and must start and end with a letter or digit.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a nonce to sign",
        "tags": [
          "aliases"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "aliases:challenge",
            "limit": 30,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/aliases": {
      "post": {
        "description": "Takes the `nonce` of a `CLAIM` challenge from `POST /v1/aliases/challenges` and the signature over its message: the address, chain and network registered are the challenge's, never the body's, and that address becomes the alias's primary. A challenge is single-use and lives 5 minutes (`alias_challenge_invalid`); a signature that does not verify is `alias_signature_invalid`. `email` is the mailbox recovery goes to, a consumer holds at most 25 aliases (`400 alias_address_conflict`) and the first claim of a name wins (`409 alias_taken`).\n\nRequires the `payments:write` scope.",
        "operationId": "AliasesController_claim_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimAliasDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnedAliasEntity"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`alias_name_invalid`: Reserved, malformed, or the wrong length\n\n`alias_challenge_invalid`: No challenge, expired, already spent, or issued for other details\n\n`alias_signature_invalid`: The signature does not verify against the claiming address\n\n`alias_address_conflict`: The address is already on the alias, or the alias is at its cap",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_name_invalid": {
                    "summary": "alias_name_invalid: Reserved, malformed, or the wrong length",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_name_invalid",
                      "error": "Bad Request",
                      "message": "An alias may use a-z, 0-9 and underscores, and must start and end with a letter or digit.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_challenge_invalid": {
                    "summary": "alias_challenge_invalid: No challenge, expired, already spent, or issued for other details",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_challenge_invalid",
                      "error": "Bad Request",
                      "message": "The challenge is unknown, expired, already used, or was issued for different details.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_signature_invalid": {
                    "summary": "alias_signature_invalid: The signature does not verify against the claiming address",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_signature_invalid",
                      "error": "Bad Request",
                      "message": "The signature does not verify against the address that is claiming.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_address_conflict": {
                    "summary": "alias_address_conflict: The address is already on the alias, or the alias is at its cap",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_address_conflict",
                      "error": "Bad Request",
                      "message": "That address is already on this alias for that network.",
                      "path": "/v1/aliases/alice/addresses",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`alias_taken`: someone claimed the handle first. There is no queue and no reservation: pick another name.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "alias_taken": {
                    "summary": "alias_taken: The handle is already claimed: first claim wins",
                    "value": {
                      "statusCode": 409,
                      "code": "alias_taken",
                      "error": "Conflict",
                      "message": "The alias \"alice\" is already claimed.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Claim an alias with a signature",
        "tags": [
          "aliases"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      },
      "get": {
        "description": "The aliases this consumer holds, newest first, each with its recovery `email`, `status` and every address on every chain and network (primary first). Paged with `take` (default and maximum 50) and `skip`; answers `{ data, total, take, skip }`.\n\nRequires the `payments:read` scope.",
        "operationId": "AliasesController_list_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many aliases to return, at most 50.",
            "schema": {
              "default": 50,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many aliases to skip before this page.",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the caller's aliases",
        "tags": [
          "aliases"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/aliases/{name}/addresses": {
      "post": {
        "description": "Needs two proofs: the caller owns the alias, and the NEW address signs for itself. One alias may hold many addresses across many networks.\n\nRequires the `payments:write` scope.",
        "operationId": "AliasesController_addAddress_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddAliasAddressDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasAddressEntity"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`alias_challenge_invalid`: No challenge, expired, already spent, or issued for other details\n\n`alias_signature_invalid`: The signature does not verify against the claiming address\n\n`alias_address_conflict`: The address is already on the alias, or the alias is at its cap",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_challenge_invalid": {
                    "summary": "alias_challenge_invalid: No challenge, expired, already spent, or issued for other details",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_challenge_invalid",
                      "error": "Bad Request",
                      "message": "The challenge is unknown, expired, already used, or was issued for different details.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_signature_invalid": {
                    "summary": "alias_signature_invalid: The signature does not verify against the claiming address",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_signature_invalid",
                      "error": "Bad Request",
                      "message": "The signature does not verify against the address that is claiming.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_address_conflict": {
                    "summary": "alias_address_conflict: The address is already on the alias, or the alias is at its cap",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_address_conflict",
                      "error": "Bad Request",
                      "message": "That address is already on this alias for that network.",
                      "path": "/v1/aliases/alice/addresses",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Point the alias at another address",
        "tags": [
          "aliases"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/aliases/{name}/addresses/{addressId}": {
      "delete": {
        "description": "Deletes one address of an alias this consumer holds. When it was the primary on its chain and network, the oldest remaining address there becomes primary. The last address of the alias cannot be removed: release the alias instead.\n\nRequires the `payments:write` scope.",
        "operationId": "AliasesController_removeAddress_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "addressId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasDeletedEntity"
                }
              }
            }
          },
          "400": {
            "description": "`alias_address_conflict`: an alias must keep at least one address. Release the alias instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "alias_address_conflict": {
                    "summary": "alias_address_conflict: The address is already on the alias, or the alias is at its cap",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_address_conflict",
                      "error": "Bad Request",
                      "message": "That address is already on this alias for that network.",
                      "path": "/v1/aliases/alice/addresses",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Remove one address from the alias",
        "tags": [
          "aliases"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/aliases/{name}": {
      "delete": {
        "description": "Deletes an alias this consumer holds, with all its addresses, so anyone can claim the name again. An alias held by another consumer is a 404.\n\nRequires the `payments:write` scope.",
        "operationId": "AliasesController_release_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Release the alias back to the namespace",
        "tags": [
          "aliases"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/aliases/{name}/recovery": {
      "post": {
        "description": "Always `{ accepted: true }`, whether or not the alias exists and the mailbox matched: a handle is public and the mailbox behind it is not. When both match, the token is emailed to the mailbox on record (at most once a minute per alias); it never appears in the response.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "AliasesController_startRecovery_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartAliasRecoveryDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AliasRecoveryStartedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "`misconfigured`: A server-side configuration error: retrying will not help",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "BlindPay (prod) is not configured: set BLINDPAY_INSTANCE_ID_PROD.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Start email recovery: the token is emailed to the owner",
        "tags": [
          "aliases"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "aliases:recovery-start",
            "limit": 5,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-uniform-answer": true
      }
    },
    "/v1/aliases/{name}/recovery/complete": {
      "post": {
        "description": "Needs the emailed token AND a signature from the new key. Every previous address is dropped: recovery exists because the old keys are gone, and leaving them resolvable would keep whoever holds them receiving payments.\n\nRequires the `payments:write` scope.",
        "operationId": "AliasesController_completeRecovery_v1",
        "parameters": [
          {
            "name": "name",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompleteAliasRecoveryDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OwnedAliasEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`alias_recovery_invalid`: The recovery token is unknown, expired or already spent\n\n`alias_signature_invalid`: The signature does not verify against the claiming address\n\n`alias_address_conflict`: The address is already on the alias, or the alias is at its cap",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_recovery_invalid": {
                    "summary": "alias_recovery_invalid: The recovery token is unknown, expired or already spent",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_recovery_invalid",
                      "error": "Bad Request",
                      "message": "The recovery token is unknown, expired or already used.",
                      "path": "/v1/aliases/alice/recovery/complete",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_signature_invalid": {
                    "summary": "alias_signature_invalid: The signature does not verify against the claiming address",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_signature_invalid",
                      "error": "Bad Request",
                      "message": "The signature does not verify against the address that is claiming.",
                      "path": "/v1/aliases",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "alias_address_conflict": {
                    "summary": "alias_address_conflict: The address is already on the alias, or the alias is at its cap",
                    "value": {
                      "statusCode": 400,
                      "code": "alias_address_conflict",
                      "error": "Bad Request",
                      "message": "That address is already on this alias for that network.",
                      "path": "/v1/aliases/alice/addresses",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Finish recovery: take ownership with a new address",
        "tags": [
          "aliases"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "aliases:recovery-complete",
            "limit": 10,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/wallet/auth/providers": {
      "get": {
        "description": "Render buttons from this rather than from a compiled-in list. A deployment with no Google credentials should not show a Google button that dies at the consent screen.\n\nRequires the `payments:read` scope. The shared public key may call it.",
        "operationId": "WalletAuthController_providers_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletAuthProvidersEntity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Which sign-in doors this deployment has",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/wallet/auth/oauth/authorize": {
      "post": {
        "description": "Returns the URL to open in a browser. Keep the PKCE verifier on the device: the `state` travels through the browser and buys only polling, while the verifier is what redeems the handshake.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "WalletAuthController_startOauth_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartWalletOauthDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletOauthStartedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`wallet_provider_unavailable`: That provider is unknown, or not configured on this deployment\n\n`wallet_return_url_not_allowed`: The return URL is not one this deployment redirects to",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_provider_unavailable": {
                    "summary": "wallet_provider_unavailable: That provider is unknown, or not configured on this deployment",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_provider_unavailable",
                      "error": "Bad Request",
                      "message": "google sign-in is not configured on this deployment.",
                      "path": "/v1/wallet/auth/oauth/authorize",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "wallet_return_url_not_allowed": {
                    "summary": "wallet_return_url_not_allowed: The return URL is not one this deployment redirects to",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_return_url_not_allowed",
                      "error": "Bad Request",
                      "message": "returnTo is not one of this deployment’s wallet return URLs (WALLET_AUTH_RETURN_URLS).",
                      "path": "/v1/wallet/auth/oauth/authorize",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "`wallet_provider_unavailable`: That provider is unknown, or not configured on this deployment",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_provider_unavailable": {
                    "summary": "wallet_provider_unavailable: That provider is unknown, or not configured on this deployment",
                    "value": {
                      "statusCode": 503,
                      "code": "wallet_provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "google sign-in is not configured on this deployment.",
                      "path": "/v1/wallet/auth/oauth/authorize",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Open a provider sign-in",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-auth-authorize",
            "limit": 20,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/wallet/auth/oauth/callback/{provider}": {
      "get": {
        "description": "Not called by your code: the person’s browser lands here. Public by necessity: a navigation carries no API key and no gateway consumer. It renders a page (or, when the handshake was opened with a `returnTo`, redirects to it with the `state`) and nothing else; the identity is collected by the device that holds the PKCE verifier. Register `{WALLET_AUTH_PUBLIC_BASE_URL}/v1/wallet/auth/oauth/callback/{provider}` with each provider.",
        "operationId": "WalletAuthController_callback_v1",
        "parameters": [
          {
            "name": "provider",
            "required": true,
            "in": "path",
            "schema": {
              "enum": [
                "authentik",
                "google",
                "github"
              ],
              "type": "string"
            }
          },
          {
            "name": "error",
            "required": false,
            "in": "query",
            "description": "Sent by the provider when the person declined or the authorization failed. Any value ends a pending handshake `denied`, and no code is exchanged.",
            "schema": {}
          },
          {
            "name": "state",
            "required": false,
            "in": "query",
            "description": "The handshake's `state`, as `POST /v1/wallet/auth/oauth/authorize` answered it. Missing, unknown, for another provider, no longer pending or past its expiry: the callback reports `expired` and changes nothing.",
            "schema": {}
          },
          {
            "name": "code",
            "required": false,
            "in": "query",
            "description": "The authorization code the provider issued, which this service exchanges with the provider for the person's identity. Missing, a pending handshake ends `denied`.",
            "schema": {}
          }
        ],
        "responses": {
          "200": {
            "description": "A \"you can go back to your wallet\" page. It never contains the identity or a token.",
            "content": {
              "text/html": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "302": {
            "description": "The handshake was opened with a `returnTo`: the browser is sent there with `?state=…`, plus `&error=<reason>` when the sign-in did not succeed. The same reason tokens the poll reports; never the identity.",
            "headers": {
              "Location": {
                "description": "The wallet return URL with `state` (and `error`).",
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Where the provider returns the browser after consent",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public": true,
        "security": []
      }
    },
    "/v1/wallet/auth/oauth/session/{state}": {
      "get": {
        "description": "Answers on the `state` alone, and never returns the identity at any status. Poll until it leaves `pending`, then redeem with the verifier.\n\nRequires the `payments:read` scope. The shared public key may call it.",
        "operationId": "WalletAuthController_pollStatus_v1",
        "parameters": [
          {
            "name": "state",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletAuthStatusEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Poll a sign-in",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-auth-poll",
            "limit": 600,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/wallet/auth/oauth/claim": {
      "post": {
        "description": "A NEW email ends here, with a session token. An email that ALREADY has an account gets `verify_email` instead and a code in its inbox: a provider proves who consented, not who opened the sign-in, and an existing account is where the backup worth stealing is. An Authentik email the provider has not confirmed also gets `verify_email`, account or not, under the same per-address cooldown as `email/start`. The exception is a sign-in through Authentik’s emailed link (the `email` source), whose ID token carries `cosmos_inbox_proven: true`: that login already proved the inbox, so an existing account ends here too, with its backups and the `idToken`.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "WalletAuthController_claimOauth_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimWalletOauthDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/WalletAuthReadyEntity"
                    },
                    {
                      "$ref": "#/components/schemas/WalletAuthVerifyEmailEntity"
                    }
                  ]
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`wallet_verifier_invalid`: The PKCE verifier does not match the handshake\n\n`wallet_login_code_cooldown`: Another code was sent to this mailbox moments ago",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_verifier_invalid": {
                    "summary": "wallet_verifier_invalid: The PKCE verifier does not match the handshake",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_verifier_invalid",
                      "error": "Bad Request",
                      "message": "The verifier does not match this handshake.",
                      "path": "/v1/wallet/auth/oauth/claim",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "wallet_login_code_cooldown": {
                    "summary": "wallet_login_code_cooldown: Another code was sent to this mailbox moments ago",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_login_code_cooldown",
                      "error": "Bad Request",
                      "message": "A code was just sent to that address. Wait a moment before asking for another.",
                      "path": "/v1/wallet/auth/email/start",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Redeem a handshake with the PKCE verifier",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-auth-claim",
            "limit": 30,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/wallet/auth/email/start": {
      "post": {
        "description": "Emails a six-digit code to `email`, valid 15 minutes (`expiresInSeconds`), and answers a `claimToken` naming that code; send both to `POST /v1/wallet/auth/email/verify`. One mailbox gets at most one code a minute and 10 in 24 hours, whoever asks: more is `400 wallet_login_code_cooldown`. Only SHA-256 hashes of the code and the claim token are stored.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "WalletAuthController_startEmail_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/StartWalletEmailDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletEmailStartedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`wallet_login_code_cooldown`: Another code was sent to this mailbox moments ago",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_login_code_cooldown": {
                    "summary": "wallet_login_code_cooldown: Another code was sent to this mailbox moments ago",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_login_code_cooldown",
                      "error": "Bad Request",
                      "message": "A code was just sent to that address. Wait a moment before asking for another.",
                      "path": "/v1/wallet/auth/email/start",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Send a sign-in code to a mailbox",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-auth-email",
            "limit": 5,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/wallet/auth/email/verify": {
      "post": {
        "description": "Wrong codes are counted on the row, not by the client. Five burns it, and a burned code is replaced by asking for another.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "WalletAuthController_verifyEmail_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VerifyWalletEmailDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/WalletAuthReadyEntity"
                    },
                    {
                      "$ref": "#/components/schemas/WalletCodeInvalidEntity"
                    }
                  ]
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Answer a sign-in code",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-auth-claim",
            "limit": 30,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/wallet/auth/finish": {
      "post": {
        "description": "Send the session token as `X-Wallet-Session: {sessionToken}`. The gateway strips `Authorization`. The signature covers exactly:\n\n```\nCosmos Pay Wallet sign-in\nemail: {lowercased email}\naccount: {address}\nat: {signedAt}\n```\n\nsigned over those raw UTF-8 bytes with the account key, base64. The first line is one no Stellar transaction envelope can begin with, which is what makes signing it safe.\n\nOn Solana and Monad (`chain`), a `chain: {chain}` line follows the first one. Solana signs the bytes with ed25519 (`signMessage`; base64 or base58); Monad with EIP-191 `personal_sign` (0x-hex).\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "WalletAuthController_finish_v1",
        "parameters": [
          {
            "name": "X-Wallet-Session",
            "in": "header",
            "description": "{sessionToken}, from the sign-in that just finished. `Authorization: Bearer {sessionToken}` is read too, but only on a direct call: APISIX strips it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FinishWalletSignInDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletSignInFinishedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`wallet_signature_invalid`: The signature does not verify, or its timestamp is out of window\n\n`wallet_backup_invalid`: Not a backup box this service will keep\n\n`wallet_backup_limit`: The account already keeps as many wallet backups as it may",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_signature_invalid": {
                    "summary": "wallet_signature_invalid: The signature does not verify, or its timestamp is out of window",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_signature_invalid",
                      "error": "Bad Request",
                      "message": "The signature does not verify against that account.",
                      "path": "/v1/wallet/auth/finish",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "wallet_backup_invalid": {
                    "summary": "wallet_backup_invalid: Not a backup box this service will keep",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_backup_invalid",
                      "error": "Bad Request",
                      "message": "That is not a backup box this service will keep.",
                      "path": "/v1/wallet/backup",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "wallet_backup_limit": {
                    "summary": "wallet_backup_limit: The account already keeps as many wallet backups as it may",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_backup_limit",
                      "error": "Bad Request",
                      "message": "This account already keeps 20 wallet backups.",
                      "path": "/v1/wallet/auth/finish",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`wallet_session_invalid`: The sign-in token is missing, expired, or was not minted here",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_session_invalid": {
                    "summary": "wallet_session_invalid: The sign-in token is missing, expired, or was not minted here",
                    "value": {
                      "statusCode": 401,
                      "code": "wallet_session_invalid",
                      "error": "Unauthorized",
                      "message": "This sign-in has expired. Start again.",
                      "path": "/v1/wallet/auth/finish",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Attach the proven identity to the account this device signs for",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-auth-finish",
            "limit": 20,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/wallet/backup": {
      "put": {
        "description": "What `changePassword` on the device sends. No session: the signature is the credential, and it covers the SHA-256 of the box, so one signature stores exactly one box and cannot be replayed to store another. The bytes are:\n\n```\nCosmos Pay Wallet backup\naccount: {address}\nbox: {sha256 hex of box}\nat: {signedAt}\n```\n\nOn Solana and Monad a `chain: {chain}` line follows the first one, and the bytes are signed as for sign-in.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "WalletBackupController_replaceBackup_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ReplaceWalletBackupDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletBackupUpdatedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`wallet_signature_invalid`: The signature does not verify, or its timestamp is out of window\n\n`wallet_backup_invalid`: Not a backup box this service will keep",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_signature_invalid": {
                    "summary": "wallet_signature_invalid: The signature does not verify, or its timestamp is out of window",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_signature_invalid",
                      "error": "Bad Request",
                      "message": "The signature does not verify against that account.",
                      "path": "/v1/wallet/auth/finish",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "wallet_backup_invalid": {
                    "summary": "wallet_backup_invalid: Not a backup box this service will keep",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_backup_invalid",
                      "error": "Bad Request",
                      "message": "That is not a backup box this service will keep.",
                      "path": "/v1/wallet/backup",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "`wallet_account_mismatch`: No backup is stored for the account that signed",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_account_mismatch": {
                    "summary": "wallet_account_mismatch: No backup is stored for the account that signed",
                    "value": {
                      "statusCode": 404,
                      "code": "wallet_account_mismatch",
                      "error": "Not Found",
                      "message": "No backup is stored for that account.",
                      "path": "/v1/wallet/backup",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Replace the sealed box stored for an account",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-auth-finish",
            "limit": 20,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/v1/wallet/recovery/setup": {
      "post": {
        "description": "Send the session token as `X-Wallet-Session: {sessionToken}`. The gateway strips `Authorization`. The signature covers exactly:\n\n```\nCosmos Pay Wallet recovery setup\naccount: {stellarAddress}\nsigners: {signerA},{signerB}\nat: {signedAt}\n```\n\nThe envelope comes back signed by the sponsor only. Once per account: refused when the account already has a signer besides its master key.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "WalletBackupController_sponsorRecoverySetup_v1",
        "parameters": [
          {
            "name": "X-Wallet-Session",
            "in": "header",
            "description": "{sessionToken}. `Authorization: Bearer {sessionToken}` is read too, but only on a direct call: APISIX strips it.",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SponsorRecoverySetupDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletRecoverySetupEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`wallet_signature_invalid`: The signature does not verify, or its timestamp is out of window",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_signature_invalid": {
                    "summary": "wallet_signature_invalid: The signature does not verify, or its timestamp is out of window",
                    "value": {
                      "statusCode": 400,
                      "code": "wallet_signature_invalid",
                      "error": "Bad Request",
                      "message": "The signature does not verify against that account.",
                      "path": "/v1/wallet/auth/finish",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "`wallet_session_invalid`: The sign-in token is missing, expired, or was not minted here",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_session_invalid": {
                    "summary": "wallet_session_invalid: The sign-in token is missing, expired, or was not minted here",
                    "value": {
                      "statusCode": 401,
                      "code": "wallet_session_invalid",
                      "error": "Unauthorized",
                      "message": "This sign-in has expired. Start again.",
                      "path": "/v1/wallet/auth/finish",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`wallet_recovery_setup_refused`: The account cannot be sponsored: missing, or already has signers",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "wallet_recovery_setup_refused": {
                    "summary": "wallet_recovery_setup_refused: The account cannot be sponsored: missing, or already has signers",
                    "value": {
                      "statusCode": 409,
                      "code": "wallet_recovery_setup_refused",
                      "error": "Conflict",
                      "message": "This account already has signers besides its own key; sponsorship is for a first setup only.",
                      "path": "/v1/wallet/recovery/setup",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Sponsor the reserve of an account's two recovery signers",
        "tags": [
          "wallet-auth"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "wallet-recovery-setup",
            "limit": 5,
            "windowMs": 600000
          },
          {
            "name": "wallet-recovery-setup-global",
            "limit": 200,
            "windowMs": 600000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ]
      }
    },
    "/.well-known/stellar.toml": {
      "get": {
        "description": "WEB_AUTH_ENDPOINT and SIGNING_KEY (SEP-10), HOME_DOMAIN, and a [[RECOVERY_SERVERS]] entry with the SEP-30 ENDPOINT, the ROLE and the identity methods. 404 on a deployment that is not a recovery server.",
        "operationId": "StellarTomlController_toml",
        "parameters": [
          {
            "name": "network",
            "required": false,
            "in": "query",
            "description": "The ledger the file describes, `public` or `testnet`: its SEP-10 and SEP-30 endpoints then carry that ledger as a path segment. Omit for the deployment default. Any other value, or a ledger not in RECOVERY_NETWORKS, is a 404.",
            "schema": {
              "example": "testnet",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "text/plain": {
                "schema": {
                  "type": "string"
                }
              }
            },
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "SEP-1 discovery for this recovery server",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "security": []
      }
    },
    "/v1/sep10/auth": {
      "get": {
        "description": "Public: no API key. Answers a SEP-10 challenge transaction for `account` (a `G...` address) with the `network_passphrase` to sign it for; sign it with the account and exchange it at `POST /v1/sep10/auth`. Sequence 0: unsubmittable by construction. Errors have the SEP body `{ \"error\": \"...\" }`; a deployment that is not a recovery server answers 404.",
        "operationId": "Sep10Controller_challenge_v1",
        "parameters": [
          {
            "name": "account",
            "required": true,
            "in": "query",
            "description": "The Stellar account (G…) to authenticate.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "A challenge for an account",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep10-challenge",
            "limit": 60,
            "windowMs": 600000
          }
        ],
        "security": []
      },
      "post": {
        "description": "Weighed against the account's CURRENT signers and medium threshold, so a recovered account authenticates with the key that replaced its master.",
        "operationId": "Sep10Controller_token_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Sep10TokenDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Exchange a signed challenge for a token",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep10-token",
            "limit": 60,
            "windowMs": 600000
          }
        ],
        "x-cosmos-upstream": [
          "Horizon"
        ],
        "security": []
      }
    },
    "/v1/sep30/identity": {
      "post": {
        "description": "SEP-30 \"external\" authentication. The ID token is verified against the provider's published keys, must stand for a login in the last 15 minutes, must carry a VERIFIED email, and is accepted once per server.",
        "operationId": "Sep30Controller_exchange_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecoveryIdTokenDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Exchange an OIDC ID token for this server's identity token",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "recovery-identity",
            "limit": 30,
            "windowMs": 600000
          }
        ],
        "security": []
      }
    },
    "/v1/sep30/identity/email/start": {
      "post": {
        "description": "The same answer whether or not the address recovers anything here; a code is only sent to one that does.",
        "operationId": "Sep30Controller_startEmail_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecoveryEmailStartDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Email a code that proves an inbox to this server",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "recovery-email",
            "limit": 5,
            "windowMs": 600000
          }
        ],
        "security": []
      }
    },
    "/v1/sep30/identity/email/verify": {
      "post": {
        "description": "Public: no API key. Send the `claim_token` from `POST /v1/sep30/identity/email/start` with the emailed `code`: the right answer is `status: ready` with this server's identity token for that inbox, once; a wrong one is `invalid` with `attempts_left`, and an unknown, used or lapsed claim is `expired`. Five wrong answers burn it (`locked`).",
        "operationId": "Sep30Controller_verifyEmail_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecoveryEmailVerifyDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Answer an emailed code",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "recovery-code",
            "limit": 30,
            "windowMs": 600000
          }
        ],
        "security": []
      }
    },
    "/v1/sep30/accounts": {
      "get": {
        "description": "A SEP-10 token lists its own account when it is registered here; this server's identity token for an email lists every account naming that email. It reads one ledger (the one the path names, e.g. `/v1/sep30/testnet/accounts`, or the default) and answers up to 100 accounts per page in address order as `{ accounts }`; pass the last address as `after` for the next page. Errors have the SEP body `{ \"error\": \"...\" }`: 401 without a valid token from this server, 404 on a deployment that is not a recovery server.",
        "operationId": "Sep30Controller_list_v1",
        "parameters": [
          {
            "name": "after",
            "required": false,
            "in": "query",
            "description": "The last address of the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Accounts this caller may recover (paged by `after`)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep30-read",
            "limit": 120,
            "windowMs": 600000
          }
        ]
      }
    },
    "/v1/sep30/accounts/{address}": {
      "post": {
        "description": "Stores who may recover `address` (1 to 3 identities, roles `owner`, `sender` or `receiver`, each with 1 to 3 `email` auth methods) and answers the account with `signers`: this server's key for it. Only a SEP-10 token of that same account may call it (403 otherwise), and an account already registered here is a 409: change it with `PUT`. Errors have the SEP body `{ \"error\": \"...\" }`: 401 without a valid token from this server, 404 on a deployment that is not a recovery server.",
        "operationId": "Sep30Controller_register_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Sep30IdentitiesDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Register an account (SEP-10 token of that account)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep30-write",
            "limit": 30,
            "windowMs": 600000
          }
        ]
      },
      "put": {
        "description": "Replaces the identities of `address`, never merging them with the old ones, and registers the account if it is not here yet. Only a SEP-10 token of that same account may call it (403 otherwise); it answers the account as `POST` does. Errors have the SEP body `{ \"error\": \"...\" }`: 401 without a valid token from this server, 404 on a deployment that is not a recovery server.",
        "operationId": "Sep30Controller_update_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Sep30IdentitiesDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Replace who may recover an account (SEP-10 token of that account)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep30-write",
            "limit": 30,
            "windowMs": 600000
          }
        ]
      },
      "get": {
        "description": "The account's identity roles, flagging the one the token authenticates as, and this server's signer key for it. Takes the account's SEP-10 token, or this server's identity token for an email registered on it; an account that is absent and one the token may not act on are the same 404. Errors have the SEP body `{ \"error\": \"...\" }`: 401 without a valid token from this server, 404 on a deployment that is not a recovery server.",
        "operationId": "Sep30Controller_get_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Describe an account",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep30-read",
            "limit": 120,
            "windowMs": 600000
          }
        ]
      },
      "delete": {
        "description": "Deletes the registration and its identities and answers the account as it was. Only a SEP-10 token of that same account may call it (403 otherwise); an account not registered here is a 404. Errors have the SEP body `{ \"error\": \"...\" }`: 401 without a valid token from this server, 404 on a deployment that is not a recovery server.",
        "operationId": "Sep30Controller_remove_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Forget an account (SEP-10 token of that account)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep30-write",
            "limit": 30,
            "windowMs": 600000
          }
        ]
      }
    },
    "/v1/sep30/accounts/{address}/sign/{signer}": {
      "post": {
        "description": "Returns the SIGNATURE, not an envelope. Only an account-control change on the registered account, sourced by it, with no memo, valid for at most 15 minutes.",
        "operationId": "Sep30Controller_sign_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Sep30SignDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Co-sign a recovery transaction",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "sep30-sign",
            "limit": 20,
            "windowMs": 600000
          }
        ]
      }
    },
    "/v1/sep30/shares": {
      "get": {
        "description": "This server's identity token for an email. One proof brings back the halves of every wallet backed up under it.",
        "operationId": "RecoverySharesController_list_v1",
        "parameters": [
          {
            "name": "after",
            "required": false,
            "in": "query",
            "description": "The last address of the previous page.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Every half this server holds for the proven inbox (paged by `after`)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "recovery-share-read",
            "limit": 20,
            "windowMs": 600000
          }
        ]
      }
    },
    "/v1/sep30/shares/{address}": {
      "put": {
        "description": "Replaces any half filed before: a re-sealed backup has a new key. The email is who may take the half back.",
        "operationId": "RecoverySharesController_put_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RecoveryShareDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "File this server's half of a backup's recovery key (SEP-10 token of that account)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "recovery-share-write",
            "limit": 30,
            "windowMs": 600000
          }
        ]
      },
      "get": {
        "description": "The account's SEP-10 token, or this server's identity token for the email the half was filed under. Absent and not-yours are the same 404.",
        "operationId": "RecoverySharesController_get_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Take this server's half back (the account's key, or its proven inbox)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "recovery-share-read",
            "limit": 20,
            "windowMs": 600000
          }
        ]
      },
      "delete": {
        "description": "Deletes this server's half of the backup recovery key filed for `address` and answers `{ address }`. Only a SEP-10 token of that same account may call it (403 otherwise); no half filed here is a 404. Errors have the SEP body `{ \"error\": \"...\" }`: 401 without a valid token from this server, 404 on a deployment that is not a recovery server.",
        "operationId": "RecoverySharesController_remove_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "security": [
          {
            "sep-token": []
          }
        ],
        "summary": "Forget this server's half (SEP-10 token of that account)",
        "tags": [
          "recovery"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "recovery-share-write",
            "limit": 30,
            "windowMs": 600000
          }
        ]
      }
    },
    "/v1/plugins": {
      "get": {
        "description": "Each plugin with its manifest (`capabilities`, `egress`, `config` settings, `queries`, `commands`, `events`) and `installation`: this consumer's installation of it, or null. An installation lists `pendingCapabilities` when the plugin was updated to ask for more than was granted, and its actions are refused until it is installed again. Answers `{ data }`, not paged.\n\nRequires the `plugins:read` scope.",
        "operationId": "PluginsController_list_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginListEntity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the plugins this deployment serves, with this key’s installations",
        "tags": [
          "plugins"
        ],
        "x-cosmos-scopes": [
          "plugins:read"
        ]
      }
    },
    "/v1/plugins/{slug}": {
      "get": {
        "description": "One plugin's manifest and this consumer's `installation` of it (null when not installed). Read it before installing: `PUT /v1/plugins/{slug}/installation` must grant exactly the `capabilities` listed here. Secret settings are never returned; `installation.secretsSet` names the ones that hold a value.\n\nRequires the `plugins:read` scope.",
        "operationId": "PluginsController_describe_v1",
        "parameters": [
          {
            "name": "slug",
            "required": true,
            "in": "path",
            "description": "The plugin, e.g. `example`.",
            "schema": {
              "example": "example",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Describe a plugin: capabilities, egress, settings, actions",
        "tags": [
          "plugins"
        ],
        "x-cosmos-scopes": [
          "plugins:read"
        ]
      }
    },
    "/v1/plugins/{slug}/installation": {
      "put": {
        "description": "Installing is consent: `grantCapabilities` must list exactly the capabilities the plugin declares, no more and no fewer (`400 plugin_consent_mismatch`). `config` is checked against the plugin's settings; secret settings are stored sealed and kept when not sent again. Call it again after an update leaves `pendingCapabilities`; it answers the plugin with its new `installation`.\n\nRequires the `plugins:write` scope.",
        "operationId": "PluginsController_install_v1",
        "parameters": [
          {
            "name": "slug",
            "required": true,
            "in": "path",
            "description": "The plugin, e.g. `example`.",
            "schema": {
              "example": "example",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InstallPluginDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginEntity"
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`plugin_consent_mismatch`: grantCapabilities must list exactly the capabilities the plugin declares",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "config.apiKey is required"
                      ],
                      "path": "/v1/plugins/example/installation",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "plugin_consent_mismatch": {
                    "summary": "plugin_consent_mismatch: grantCapabilities must list exactly the capabilities the plugin declares",
                    "value": {
                      "statusCode": 400,
                      "code": "plugin_consent_mismatch",
                      "error": "Bad Request",
                      "message": "grantCapabilities must be exactly the capabilities example declares: payment_intents:read",
                      "path": "/v1/plugins/example/installation",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Install a plugin (or re-consent / reconfigure it), granting its capabilities",
        "tags": [
          "plugins"
        ],
        "x-cosmos-scopes": [
          "plugins:write"
        ]
      },
      "delete": {
        "description": "Deletes this consumer's installation and, with it, everything the plugin stored for the consumer. It works even when the deployment no longer serves the plugin; a plugin that is not installed is a 404. Answers `{ slug, uninstalled: true }`.\n\nRequires the `plugins:write` scope.",
        "operationId": "PluginsController_uninstall_v1",
        "parameters": [
          {
            "name": "slug",
            "required": true,
            "in": "path",
            "description": "The plugin, e.g. `example`.",
            "schema": {
              "example": "example",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginUninstalledEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Uninstall a plugin and delete every record it kept for this key",
        "tags": [
          "plugins"
        ],
        "x-cosmos-scopes": [
          "plugins:write"
        ]
      }
    },
    "/v1/plugins/{slug}/queries/{action}": {
      "post": {
        "description": "Runs one of the plugin's `queries` with `input` (JSON, at most 64 KiB) and answers its `output`; a query cannot write the plugin storage, customers or products. The plugin must be installed with every capability it now asks for (`409 plugin_not_installed`). A refusal by the plugin is `400 plugin_rejected`, a failure `502 plugin_failed`, and a run over 10 seconds `504 plugin_failed`.\n\nRequires the `plugins:read` scope.",
        "operationId": "PluginsController_query_v1",
        "parameters": [
          {
            "name": "slug",
            "required": true,
            "in": "path",
            "description": "The plugin, e.g. `example`.",
            "schema": {
              "example": "example",
              "type": "string"
            }
          },
          {
            "name": "action",
            "required": true,
            "in": "path",
            "description": "An action the plugin lists under `queries` / `commands`.",
            "schema": {
              "example": "get-notes",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvokePluginActionDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginActionResultEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`plugin_rejected`: The plugin refused the input; the message is the plugin’s own",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "input must be at most 65536 bytes as JSON",
                      "path": "/v1/plugins/example/queries/get-notes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "plugin_rejected": {
                    "summary": "plugin_rejected: The plugin refused the input; the message is the plugin’s own",
                    "value": {
                      "statusCode": 400,
                      "code": "plugin_rejected",
                      "error": "Bad Request",
                      "message": "paymentIntentId must be a non-empty string of at most 64 characters",
                      "path": "/v1/plugins/example/commands/add-note",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`plugin_not_installed`: The plugin is not installed for this key, or its consent is out of date",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "plugin_not_installed": {
                    "summary": "plugin_not_installed: The plugin is not installed for this key, or its consent is out of date",
                    "value": {
                      "statusCode": 409,
                      "code": "plugin_not_installed",
                      "error": "Conflict",
                      "message": "Plugin example is not installed. Install it with PUT /v1/plugins/example/installation.",
                      "path": "/v1/plugins/example/queries/get-notes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "`plugin_failed`: The plugin failed or timed out (the detail is logged, never returned)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "plugin_failed": {
                    "summary": "plugin_failed: The plugin failed or timed out (the detail is logged, never returned)",
                    "value": {
                      "statusCode": 502,
                      "code": "plugin_failed",
                      "error": "Bad Gateway",
                      "message": "Plugin example failed while handling get-notes.",
                      "path": "/v1/plugins/example/queries/get-notes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "description": "`plugin_failed`: The plugin failed or timed out (the detail is logged, never returned)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "plugin_failed": {
                    "summary": "plugin_failed: The plugin ran out of time",
                    "value": {
                      "statusCode": 504,
                      "code": "plugin_failed",
                      "error": "Gateway Timeout",
                      "message": "Plugin example did not respond in time.",
                      "path": "/v1/plugins/example/queries/get-notes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Run a read-only plugin action",
        "tags": [
          "plugins"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "plugins:action",
            "limit": 120,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "plugins:read"
        ]
      }
    },
    "/v1/plugins/{slug}/commands/{action}": {
      "post": {
        "description": "Runs one of the plugin's `commands` with `input` (JSON, at most 64 KiB) and answers its `output`; a command may write its own storage and, as far as the granted capabilities allow, this consumer's customers and products. It needs an installation with every capability the plugin now asks for (`409 plugin_not_installed`), and storage is capped per installation (`409 plugin_quota_exceeded`). A refusal by the plugin is `400 plugin_rejected`, a failure `502 plugin_failed`, and a run over 10 seconds `504 plugin_failed`.\n\nRequires the `plugins:write` scope.",
        "operationId": "PluginsController_command_v1",
        "parameters": [
          {
            "name": "slug",
            "required": true,
            "in": "path",
            "description": "The plugin, e.g. `example`.",
            "schema": {
              "example": "example",
              "type": "string"
            }
          },
          {
            "name": "action",
            "required": true,
            "in": "path",
            "description": "An action the plugin lists under `queries` / `commands`.",
            "schema": {
              "example": "add-note",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InvokePluginActionDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PluginActionResultEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`plugin_rejected`: The plugin refused the input; the message is the plugin’s own",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "input must be at most 65536 bytes as JSON",
                      "path": "/v1/plugins/example/queries/get-notes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "plugin_rejected": {
                    "summary": "plugin_rejected: The plugin refused the input; the message is the plugin’s own",
                    "value": {
                      "statusCode": 400,
                      "code": "plugin_rejected",
                      "error": "Bad Request",
                      "message": "paymentIntentId must be a non-empty string of at most 64 characters",
                      "path": "/v1/plugins/example/commands/add-note",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`plugin_not_installed`: The plugin is not installed for this key, or its consent is out of date\n\n`plugin_quota_exceeded`: The installation holds as many records as it may",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "plugin_not_installed": {
                    "summary": "plugin_not_installed: The plugin is not installed for this key, or its consent is out of date",
                    "value": {
                      "statusCode": 409,
                      "code": "plugin_not_installed",
                      "error": "Conflict",
                      "message": "Plugin example is not installed. Install it with PUT /v1/plugins/example/installation.",
                      "path": "/v1/plugins/example/queries/get-notes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "plugin_quota_exceeded": {
                    "summary": "plugin_quota_exceeded: The installation holds as many records as it may",
                    "value": {
                      "statusCode": 409,
                      "code": "plugin_quota_exceeded",
                      "error": "Conflict",
                      "message": "Plugin example has reached its limit of 10000 records.",
                      "path": "/v1/plugins/example/commands/add-note",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "`plugin_failed`: The plugin failed or timed out (the detail is logged, never returned)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "plugin_failed": {
                    "summary": "plugin_failed: The plugin failed or timed out (the detail is logged, never returned)",
                    "value": {
                      "statusCode": 502,
                      "code": "plugin_failed",
                      "error": "Bad Gateway",
                      "message": "Plugin example failed while handling add-note.",
                      "path": "/v1/plugins/example/commands/add-note",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "504": {
            "description": "`plugin_failed`: The plugin failed or timed out (the detail is logged, never returned)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "plugin_failed": {
                    "summary": "plugin_failed: The plugin ran out of time",
                    "value": {
                      "statusCode": 504,
                      "code": "plugin_failed",
                      "error": "Gateway Timeout",
                      "message": "Plugin example did not respond in time.",
                      "path": "/v1/plugins/example/commands/add-note",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Run a plugin action that writes",
        "tags": [
          "plugins"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "plugins:action",
            "limit": 120,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "plugins:write"
        ]
      }
    },
    "/v1/kyc/receivers": {
      "post": {
        "description": "Stores the receiver here and sends nothing to BlindPay yet: it is created there only by `POST /v1/kyc/receivers/{id}/enable`, after the review and the customer's acceptance of the terms. A body with KYC data (tax id, date of birth, documents, legal name, formation date or owners) starts in `pending_review`, a bare registration in `inactive`. The receiver belongs to the BlindPay instance of the key's network (production for a mainnet key, development otherwise), and the stored dossier is never returned.\n\nRequires the `kyc:write` scope.",
        "operationId": "ReceiversController_create_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateReceiverDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a receiver (start KYC/KYB)",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "get": {
        "description": "Reads the local mirror only, newest first, on the BlindPay instance of the key's network. Paginated with `take` (default 100, max 100) and `skip`; answers `{ data, total, take, skip }`, where `total` counts every matching receiver. The stored KYC dossier (tax id, documents, owners) is never returned.\n\nRequires the `kyc:read` scope.",
        "operationId": "ReceiversController_findAll_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's receivers",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:read"
        ]
      }
    },
    "/v1/kyc/receivers/{id}": {
      "get": {
        "description": "For a receiver that already exists at BlindPay, reads it there and updates the local mirror first, so `kycStatus` is BlindPay's current one; when BlindPay cannot be reached, the stored row is answered instead of an error. A receiver not yet at BlindPay (`inactive`, `pending_review`, `pending_user`) is answered from the local row.\n\nRequires the `kyc:read` scope.",
        "operationId": "ReceiversController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Get a receiver (refreshes KYC status from BlindPay)",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:read"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "patch": {
        "description": "Before the receiver exists at BlindPay, the patch is merged into the stored registration, any change bumps `dossierVersion`, and editing a `pending_user` receiver (or adding KYC data to an `inactive` one) moves it to `pending_review`. After that the patch is sent to BlindPay, and a key without the admin role may change only `external_id` and `image_url`. `tos_id` is always ignored: the accepted terms cannot be changed.\n\nRequires the `kyc:write` scope.",
        "operationId": "ReceiversController_update_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateReceiverDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`kyc_review_required`: the receiver already exists at BlindPay and the patch touches a field other than `external_id` or `image_url`. Only an elevated key (admin role) may rewrite identity at the provider; before enabling, the same edit sends the receiver back to review instead.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "kyc_review_required": {
                    "summary": "kyc_review_required: The change has to be signed off with an elevated (admin) key",
                    "value": {
                      "statusCode": 403,
                      "code": "kyc_review_required",
                      "error": "Forbidden",
                      "message": "Approving a receiver requires an elevated (admin) key: the KYC review must be signed off by someone other than the key that submitted it.",
                      "path": "/v1/kyc/receivers/rc_4Kd9Wp1Lm3/approve",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Update a receiver (once it is at BlindPay, identity fields need an elevated key)",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "delete": {
        "description": "Deletes the receiver at BlindPay when it was ever created there, then the local row, and records the deletion in the audit log. A receiver that never reached BlindPay is deleted locally only.\n\nRequires the `kyc:write` scope.",
        "operationId": "ReceiversController_remove_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Delete a receiver",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/receivers/{id}/approve": {
      "post": {
        "description": "The review gate before anything reaches BlindPay: only a key with the admin role may approve (any other key gets 403 `kyc_review_required`), and only a `pending_review` receiver. It requests BlindPay's hosted terms-of-service link for `redirect_url` (https, on this consumer's allow-list), moves the receiver to `pending_user` and returns the link with the receiver's email; nothing is emailed, the caller delivers it. Send `expected_version` (the `dossierVersion` you reviewed) so an edit made since is a 409 `kyc_state_invalid` instead of an approval of unreviewed data.\n\nRequires the `kyc:write` scope.",
        "operationId": "ReceiversController_approve_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApproveReceiverDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Receiver approved; terms link returned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverApprovalEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "`kyc_review_required`: the API key is not elevated (admin role). A key may submit KYC data or approve it, not both.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "kyc_review_required": {
                    "summary": "kyc_review_required: The change has to be signed off with an elevated (admin) key",
                    "value": {
                      "statusCode": 403,
                      "code": "kyc_review_required",
                      "error": "Forbidden",
                      "message": "Approving a receiver requires an elevated (admin) key: the KYC review must be signed off by someone other than the key that submitted it.",
                      "path": "/v1/kyc/receivers/rc_4Kd9Wp1Lm3/approve",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "insufficient_scope": {
                    "summary": "insufficient_scope: The API key does not hold the scope this route requires",
                    "value": {
                      "statusCode": 403,
                      "code": "insufficient_scope",
                      "error": "Forbidden",
                      "message": "This API key is missing the required scope(s): swaps:write",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`kyc_state_invalid`: the receiver is not in 'pending_review', or the KYC data changed after you read it (`expected_version` names a version that is no longer current). Re-read the receiver, review it again, and approve that version.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "kyc_state_invalid": {
                    "summary": "kyc_state_invalid: An illegal KYC state transition, not a duplicate request",
                    "value": {
                      "statusCode": 409,
                      "code": "kyc_state_invalid",
                      "error": "Conflict",
                      "message": "Cannot move receiver from 'approved' to 'pending'",
                      "path": "/v1/kyc/receivers/rc_4Kd9Wp1Lm3",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Approve a receiver's KYC review and get its terms-of-service link",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/receivers/{id}/tos": {
      "post": {
        "description": "Only for a `pending_user` receiver (approved, terms not yet accepted); any other status is 400 `kyc_state_invalid`. Requests a fresh hosted link from BlindPay for `redirect_url` (https, on this consumer's allow-list) and returns it with the receiver's email. `channel: email` sends nothing itself: it records the send, allowed once per 24 hours per receiver (400 `validation_failed` inside that window, 409 `kyc_state_invalid` when two race), and the caller emails the returned link; `channel: code` (the default) has no such limit.\n\nRequires the `kyc:write` scope.",
        "operationId": "ReceiversController_requestTos_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RequestTosDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverTosEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Request a terms-of-service link for an approved receiver",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/receivers/{id}/enable": {
      "post": {
        "description": "Creates the receiver at BlindPay: replays the stored registration with the `tos_id` the customer got by accepting the terms, then replaces the local placeholder id with BlindPay's and mirrors BlindPay's KYC status. Only a `pending_user` receiver whose current `dossierVersion` is the approved one; otherwise, or when another enable is running, 409 `kyc_state_invalid`. A receiver already at BlindPay is not created again: it is refreshed from BlindPay and returned.\n\nRequires the `kyc:write` scope.",
        "operationId": "ReceiversController_enable_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EnableReceiverDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`kyc_state_invalid`: an invalid KYC status transition (e.g. the receiver is not in 'pending_user').",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "kyc_state_invalid": {
                    "summary": "kyc_state_invalid: An illegal KYC state transition, not a duplicate request",
                    "value": {
                      "statusCode": 409,
                      "code": "kyc_state_invalid",
                      "error": "Conflict",
                      "message": "Cannot move receiver from 'approved' to 'pending'",
                      "path": "/v1/kyc/receivers/rc_4Kd9Wp1Lm3",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Enable an inactive receiver with an accepted terms-of-service id",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/receivers/{id}/access": {
      "patch": {
        "description": "Sets `disabled` on the receiver. While disabled, onramp, offramp and adding wallets, bank accounts or virtual accounts for it are refused with 403 `account_disabled`, whatever its KYC status. Only a key with the admin role may call it (any other key gets 403 `insufficient_scope`), so a tenant cannot lift a switch an operator set. Local only: nothing is sent to BlindPay.\n\nRequires the `kyc:write` scope.",
        "operationId": "ReceiversController_setAccess_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SetAccessDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReceiverEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "description": "The API key is not elevated (admin role); a tenant key cannot lift a kill-switch an operator applied.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "insufficient_scope": {
                    "summary": "insufficient_scope: The API key does not hold the scope this route requires",
                    "value": {
                      "statusCode": 403,
                      "code": "insufficient_scope",
                      "error": "Forbidden",
                      "message": "This API key is missing the required scope(s): swaps:write",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Enable or disable a fiat account (admin-only kill-switch for onramp/offramp)",
        "tags": [
          "kyc"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ]
      }
    },
    "/v1/kyc/receivers/{receiverId}/wallets/sign-message": {
      "get": {
        "description": "Fetches from BlindPay the message the customer signs in their own wallet to prove an EOA wallet is theirs. Sign it, then register the wallet with `POST /v1/kyc/receivers/{receiverId}/wallets` and its `signature_tx_hash` instead of an `address`. Nothing is stored.\n\nRequires the `kyc:read` scope.",
        "operationId": "WalletsController_signMessage_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Get the message to sign for the secure wallet flow",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:read"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/receivers/{receiverId}/wallets": {
      "post": {
        "description": "Registers the wallet at BlindPay under the receiver and mirrors it locally. Send `address` (account abstraction or the non-secure flow), or the `signature_tx_hash` of the message from `GET /v1/kyc/receivers/{receiverId}/wallets/sign-message` (secure EOA flow). `network` is one of BlindPay's: Stellar, Solana, Tron, Ethereum, Base, Arbitrum, Polygon or one of their test networks. A disabled receiver is refused with 403 `account_disabled`.\n\nRequires the `kyc:write` scope.",
        "operationId": "WalletsController_create_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateWalletDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Register a blockchain wallet for a receiver",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "get": {
        "description": "Reads the local mirror, newest first; BlindPay is not called. Paginated with `take` (default 100, max 100) and `skip`; answers `{ data, total, take, skip }`.\n\nRequires the `kyc:read` scope.",
        "operationId": "WalletsController_findAll_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List a receiver's wallets",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:read"
        ]
      }
    },
    "/v1/kyc/receivers/{receiverId}/wallets/{id}": {
      "delete": {
        "description": "Deletes the wallet at BlindPay, then its local row. A wallet id this receiver does not have answers `deleted: true` without calling BlindPay, so repeating a delete succeeds.\n\nRequires the `kyc:write` scope.",
        "operationId": "WalletsController_remove_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WalletDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Delete a wallet",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/receivers/{receiverId}/bank-accounts": {
      "post": {
        "description": "Creates the account at BlindPay under the receiver and mirrors it; offramp payouts settle to it. `type` names the rail, and only that rail's fields are needed (`GET /v1/kyc/bank-details?rail=` lists them). The response carries identifiers only (`rail`, `name`, `country`), never the account numbers. A disabled receiver is refused with 403 `account_disabled`.\n\nRequires the `kyc:write` scope.",
        "operationId": "BankAccountsController_create_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateBankAccountDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankAccountEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Add a fiat bank account for a receiver",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "get": {
        "description": "Reads the local mirror, newest first; BlindPay is not called, and account numbers are never returned. Paginated with `take` (default 100, max 100) and `skip`; answers `{ data, total, take, skip }`.\n\nRequires the `kyc:read` scope.",
        "operationId": "BankAccountsController_findAll_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankAccountListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List a receiver's bank accounts",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:read"
        ]
      }
    },
    "/v1/kyc/receivers/{receiverId}/bank-accounts/{id}": {
      "delete": {
        "description": "Deletes the account at BlindPay, then its local row. An id this receiver does not have answers `deleted: true` without calling BlindPay, so repeating a delete succeeds.\n\nRequires the `kyc:write` scope.",
        "operationId": "BankAccountsController_remove_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BankAccountDeletedEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Delete a bank account",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/upload": {
      "post": {
        "description": "Multipart: one `file` part (JPEG, PNG, WebP, HEIC/HEIF or PDF, up to 10 MB, its bytes checked against the declared type) and an optional `bucket` (`onboarding` by default, `avatar` or `limit_increase`). BlindPay stores the file on the instance of the key's network and nothing is kept here; pass the returned `file_url` in the receiver's `*_file` fields. BlindPay keeps a stored file even when a later step fails, which is why the route is budgeted per address and per consumer.\n\nRequires the `kyc:write` scope.",
        "operationId": "KycMetaController_upload_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "bucket": {
                    "type": "string",
                    "enum": [
                      "avatar",
                      "onboarding",
                      "limit_increase"
                    ]
                  }
                },
                "required": [
                  "file"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KycUploadEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "The multipart form was refused (`validation_failed`), before the provider saw anything: more than 4 text fields; a text field longer than 1024 bytes; more than 1 file; a declared content type other than image/jpeg, image/png, image/webp, image/heic, image/heif, application/pdf; file bytes that do not match the declared content type; a missing `file` part; or an unknown `bucket`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "description": "The file is larger than 10485760 bytes (`payload_too_large`). Multer stops reading at the limit, so nothing reaches the provider.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "payload_too_large": {
                    "summary": "payload_too_large: The upload is larger than the route accepts",
                    "value": {
                      "statusCode": 413,
                      "code": "payload_too_large",
                      "error": "Payload Too Large",
                      "message": "File too large",
                      "path": "/v1/kyc/upload",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Upload a KYC document; returns its file_url",
        "tags": [
          "kyc"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "kyc:upload",
            "limit": 20,
            "windowMs": 600000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/terms-of-service": {
      "post": {
        "description": "Asks BlindPay for a hosted terms-of-service page and returns its URL; after acceptance BlindPay redirects to `redirect_url` (https, on this consumer's allow-list) with a `tos_id` query parameter. With `receiver_id` (the BlindPay id of a receiver this consumer owns, otherwise 404) the terms are for that existing receiver. `idempotency_key` is forwarded to BlindPay and generated when omitted; every call creates a record there, hence the budgets.\n\nRequires the `kyc:write` scope.",
        "operationId": "KycMetaController_initiateTos_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/InitiateTosDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/KycTermsOfServiceEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Start ToS acceptance; returns the hosted URL (first KYC step)",
        "tags": [
          "kyc"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "kyc:tos",
            "limit": 10,
            "windowMs": 600000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "kyc:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/rails": {
      "get": {
        "description": "Relays BlindPay's catalog of bank rails on the instance of the key's network (production for a mainnet key, development otherwise). Nothing is stored; the body is BlindPay's answer as returned.\n\nRequires the `kyc:read` scope.",
        "operationId": "KycMetaController_rails_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "List available bank rails",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:read"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/kyc/bank-details": {
      "get": {
        "description": "Relays BlindPay's field schema for the `rail` query parameter (required: 400 `validation_failed` without it), the fields `POST /v1/kyc/receivers/{receiverId}/bank-accounts` needs for that rail. Answered as BlindPay returns it, from the instance of the key's network.\n\nRequires the `kyc:read` scope.",
        "operationId": "KycMetaController_bankDetails_v1",
        "parameters": [
          {
            "name": "rail",
            "required": true,
            "in": "query",
            "description": "The rail whose fields to list, as a bank account's `type` names it (`GET /v1/kyc/rails` lists the rails). Forwarded to BlindPay as given.",
            "schema": {
              "example": "ach",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Get the field schema required by a rail",
        "tags": [
          "kyc-accounts"
        ],
        "x-cosmos-scopes": [
          "kyc:read"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/onramp/quotes": {
      "post": {
        "description": "Prices a payin through BlindPay for one of your wallets (`blockchain_wallet_id`, a Cosmos Pay wallet id) and records the quote as yours, on the BlindPay instance your key selects (a `dev` key uses the development instance, a `prod` key production). The quote is BlindPay's answer as is: create the payin from it before its `expires_at`. Amounts are integers in minor units, and `transfers` (AR) and `pse` (CO) need their `payer_rules`. A wallet you do not own is a 404, and one whose receiver's fiat access is disabled is `403 account_disabled`.\n\nRequires the `onramp:write` scope.",
        "operationId": "OnrampController_createQuote_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayinQuoteDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayinQuoteEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a payin quote (expires in ~5 min)",
        "tags": [
          "onramp"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "onramp:quote",
            "limit": 30,
            "windowMs": 60000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "onramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/onramp/payins": {
      "post": {
        "description": "Executes a quote from `POST /v1/onramp/quotes` at BlindPay and returns the payin with the instructions the payer follows to fund it off-platform; the destination chain is the one of the quote's wallet. Idempotent per quote: a retry of the same quote reuses its row and its BlindPay `Idempotency-Key`, so it cannot create a second payin. A quote that is not yours, is a payout quote or was minted on the other instance is `404 quote_not_found`; a lapsed one is `400 quote_expired`. Status changes arrive later as `PAYIN_UPDATED` and `PAYIN_COMPLETED` webhook events.\n\nRequires the `onramp:write` scope.",
        "operationId": "OnrampController_createPayin_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayinDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayinEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`quote_expired`: The quote is ours and yours, but past its expiry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "quote_expired": {
                    "summary": "quote_expired: The quote is ours and yours, but past its expiry",
                    "value": {
                      "statusCode": 400,
                      "code": "quote_expired",
                      "error": "Bad Request",
                      "message": "This BlindPay quote has expired. Request a new quote.",
                      "path": "/v1/onramp/payins",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a payin from a quote; returns funding instructions",
        "tags": [
          "onramp"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "onramp:payin",
            "limit": 10,
            "windowMs": 60000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "onramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "get": {
        "description": "Reads this service's mirror only (no BlindPay call), newest first, limited to your key's BlindPay instance; payins still waiting for BlindPay's id are left out. Paginated with `take` (default 100, max 100) and `skip`; answers `{ data, total, take, skip }`, where `total` counts every matching payin.\n\nRequires the `onramp:read` scope.",
        "operationId": "OnrampController_findAll_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayinListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's payins",
        "tags": [
          "onramp"
        ],
        "x-cosmos-scopes": [
          "onramp:read"
        ]
      }
    },
    "/v1/onramp/payins/{id}": {
      "get": {
        "description": "Answers from the mirror while it was updated in the last 60 seconds; an older row is refreshed from BlindPay first, and when BlindPay cannot answer the stored row is returned instead of an error. Only payins of your key's BlindPay instance that BlindPay already acknowledged; anything else is 404.\n\nRequires the `onramp:read` scope.",
        "operationId": "OnrampController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayinEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Get a payin (serves the local mirror; refreshes from BlindPay when stale)",
        "tags": [
          "onramp"
        ],
        "x-cosmos-scopes": [
          "onramp:read"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/onramp/trustline": {
      "post": {
        "description": "Asks BlindPay to build the unsigned Stellar transaction that adds the trustline `address` needs to hold the onramp's stablecoin, and returns BlindPay's answer as is. The customer signs it: this service never signs. Built on your key's BlindPay instance; nothing is stored.\n\nRequires the `onramp:write` scope.",
        "operationId": "OnrampController_createTrustline_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateTrustlineDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build an unsigned Stellar trustline tx (XDR) for the customer to sign",
        "tags": [
          "onramp"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "onramp:trustline",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "onramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/onramp/receivers/{receiverId}/virtual-accounts": {
      "post": {
        "description": "Opens a virtual account at BlindPay: a bank account in the receiver's name at `banking_partner` whose deposits are converted to `token` and sent to `blockchain_wallet_id`, a Cosmos Pay wallet id. The account is mirrored here and the mirrored row is the answer. A receiver or wallet that is not yours on your key's BlindPay instance is a 404, and the answer is `403 account_disabled` when the receiver, or the receiver that owns the wallet, has its fiat access disabled.\n\nRequires the `onramp:write` scope.",
        "operationId": "VirtualAccountsController_create_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateVirtualAccountDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created"
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a virtual account for a receiver",
        "tags": [
          "onramp"
        ],
        "x-cosmos-scopes": [
          "onramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "get": {
        "description": "Reads this service's mirror only (no BlindPay call), newest first. The receiver must be yours on your key's BlindPay instance, or the answer is 404. Paginated with `take` (default 100, max 100) and `skip`; answers `{ data, total, take, skip }`.\n\nRequires the `onramp:read` scope.",
        "operationId": "VirtualAccountsController_findAll_v1",
        "parameters": [
          {
            "name": "receiverId",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List a receiver's virtual accounts",
        "tags": [
          "onramp"
        ],
        "x-cosmos-scopes": [
          "onramp:read"
        ]
      }
    },
    "/v1/offramp/quotes": {
      "post": {
        "description": "Prices a payout through BlindPay of `token` on `network` to one of your bank accounts (`bank_account_id`, a Cosmos Pay id) and records the quote as yours, on the BlindPay instance your key selects (a `dev` key uses the development instance and moves no real money). An EVM quote carries the `contract` whose `approve` the customer signs before the payout, and `receiver_local_amount` is filled from `receiver_amount` when BlindPay sends 0. Amounts are integers in minor units. A bank account you do not own is a 404, and one whose receiver's fiat access is disabled is `403 account_disabled`.\n\nRequires the `offramp:write` scope.",
        "operationId": "OfframpController_createQuote_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayoutQuoteDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutQuoteEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a payout quote (EVM quote carries the approve contract)",
        "tags": [
          "offramp"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "offramp:quote",
            "limit": 30,
            "windowMs": 60000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "offramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/offramp/payouts/authorize": {
      "post": {
        "description": "Step one of a `stellar` or `solana` payout (EVM payouts skip it): BlindPay builds the transaction `sender_wallet_address` signs for `quote_id`, returned as `unsigned_transaction` (Stellar XDR or Solana transaction) beside BlindPay's own fields. Pass the signed result as `signed_transaction` to `POST /v1/offramp/payouts`; nothing is stored. A quote that is not yours, is a payin quote or was minted on the other instance is `404 quote_not_found`; a lapsed one is `400 quote_expired`.\n\nRequires the `offramp:write` scope.",
        "operationId": "OfframpController_authorize_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AuthorizePayoutDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizedPayoutEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`quote_expired`: The quote is ours and yours, but past its expiry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "quote_expired": {
                    "summary": "quote_expired: The quote is ours and yours, but past its expiry",
                    "value": {
                      "statusCode": 400,
                      "code": "quote_expired",
                      "error": "Bad Request",
                      "message": "This BlindPay quote has expired. Request a new quote.",
                      "path": "/v1/onramp/payins",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the unsigned Stellar/Solana payout tx to sign",
        "tags": [
          "offramp"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "offramp:payout",
            "limit": 10,
            "windowMs": 60000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "offramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/offramp/payouts": {
      "post": {
        "description": "Executes a payout quote at BlindPay: for `evm` the customer has already sent the quote's `approve`, for `stellar` and `solana` `signed_transaction` (from the authorize step) is required. Idempotent per quote: a retry of the same quote reuses its row and its BlindPay `Idempotency-Key`, so a quote is never paid out twice. A quote that is not yours, is a payin quote or was minted on the other instance is `404 quote_not_found`; a lapsed one is `400 quote_expired`. Status changes arrive later as `PAYOUT_UPDATED` and `PAYOUT_COMPLETED` webhook events.\n\nRequires the `offramp:write` scope.",
        "operationId": "OfframpController_createPayout_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreatePayoutDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: The body, query or headers failed validation\n\n`quote_expired`: The quote is ours and yours, but past its expiry",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "quote_expired": {
                    "summary": "quote_expired: The quote is ours and yours, but past its expiry",
                    "value": {
                      "statusCode": 400,
                      "code": "quote_expired",
                      "error": "Bad Request",
                      "message": "This BlindPay quote has expired. Request a new quote.",
                      "path": "/v1/onramp/payins",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Create a payout from a quote",
        "tags": [
          "offramp"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "offramp:payout",
            "limit": 10,
            "windowMs": 60000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "offramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      },
      "get": {
        "description": "Reads this service's mirror only (no BlindPay call), newest first, limited to your key's BlindPay instance; payouts still waiting for BlindPay's id are left out. Paginated with `take` (default 100, max 100) and `skip`; answers `{ data, total, take, skip }`, where `total` counts every matching payout.\n\nRequires the `offramp:read` scope.",
        "operationId": "OfframpController_findAll_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 100,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's payouts",
        "tags": [
          "offramp"
        ],
        "x-cosmos-scopes": [
          "offramp:read"
        ]
      }
    },
    "/v1/offramp/payouts/{id}": {
      "get": {
        "description": "Answers from the mirror while it was updated in the last 60 seconds; an older row is refreshed from BlindPay first, and when BlindPay cannot answer the stored row is returned instead of an error. Only payouts of your key's BlindPay instance that BlindPay already acknowledged; anything else is 404.\n\nRequires the `offramp:read` scope.",
        "operationId": "OfframpController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PayoutEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Get a payout (serves the local mirror; refreshes from BlindPay when stale)",
        "tags": [
          "offramp"
        ],
        "x-cosmos-scopes": [
          "offramp:read"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/offramp/payouts/{id}/documents": {
      "post": {
        "description": "Forwards a document backing the payout (an invoice, for example) to BlindPay and returns BlindPay's answer as is. Upload the file first with `POST /v1/kyc/upload` and pass its `file_url` as `transaction_document_file`. Only a payout of yours on your key's BlindPay instance that BlindPay already acknowledged; anything else is 404.\n\nRequires the `offramp:write` scope.",
        "operationId": "OfframpController_addDocument_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PayoutDocumentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Attach a compliance document to a payout",
        "tags": [
          "offramp"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "offramp:document",
            "limit": 20,
            "windowMs": 600000
          },
          {
            "name": "blindpay:quota",
            "limit": 60,
            "windowMs": 60000,
            "per": "consumer"
          }
        ],
        "x-cosmos-scopes": [
          "offramp:write"
        ],
        "x-cosmos-upstream": [
          "BlindPay"
        ]
      }
    },
    "/v1/defindex/vaults": {
      "get": {
        "description": "The DeFindex vaults on the key's network (a `prod` key reads mainnet, a `dev` key testnet), with DeFindex's answer passed through as is. DeFindex failures are `502 provider_error`, and a deployment without a DeFindex API key answers `503 misconfigured`.\n\nRequires the `liquidity:read` or `swaps:read` scope.",
        "operationId": "DefindexController_vaults_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Discover DeFindex vaults",
        "tags": [
          "DeFindex"
        ],
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "DeFindex"
        ]
      }
    },
    "/v1/defindex/vaults/{vault}": {
      "get": {
        "description": "One vault's details from DeFindex on the key's network, passed through as is; `vault` is its contract address (`C...`). DeFindex failures are `502 provider_error`, and a deployment without a DeFindex API key answers `503 misconfigured`.\n\nRequires the `liquidity:read` or `swaps:read` scope.",
        "operationId": "DefindexController_info_v1",
        "parameters": [
          {
            "name": "vault",
            "required": true,
            "in": "path",
            "description": "The vault's contract address (C...).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Read a DeFindex vault",
        "tags": [
          "DeFindex"
        ],
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "DeFindex"
        ]
      }
    },
    "/v1/defindex/vaults/{vault}/balance": {
      "get": {
        "description": "`account`'s shares and their underlying value in the vault, read from DeFindex on the key's network and passed through as is. DeFindex failures are `502 provider_error`, and a deployment without a DeFindex API key answers `503 misconfigured`.\n\nRequires the `liquidity:read` or `swaps:read` scope.",
        "operationId": "DefindexController_balance_v1",
        "parameters": [
          {
            "name": "vault",
            "required": true,
            "in": "path",
            "description": "The vault's contract address (C...).",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "account",
            "required": true,
            "in": "query",
            "description": "The Stellar account (G...) whose shares and their underlying value are read.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Read an account balance in a DeFindex vault",
        "tags": [
          "DeFindex"
        ],
        "x-cosmos-scopes-any": [
          "liquidity:read",
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "DeFindex"
        ]
      }
    },
    "/v1/defindex/vaults/{vault}/deposit": {
      "post": {
        "description": "DeFindex builds the deposit of `amounts` (integer strings in minor units, at most 9007199254740991 each) into the vault for `caller` on the key's network; `invest` defaults to true and `slippageBps` to 100. The returned XDR is checked to be exactly that call and recorded for this key for up to 15 minutes (less if its time bounds close sooner): sign it unchanged and send it to `POST /v1/defindex/submit`.\n\nRequires the `liquidity:write` or `swaps:write` scope.",
        "operationId": "DefindexController_deposit_v1",
        "parameters": [
          {
            "name": "vault",
            "required": true,
            "in": "path",
            "description": "The vault's contract address (C...).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DefindexDepositDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DefindexBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Build an unsigned DeFindex deposit",
        "tags": [
          "DeFindex"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "defindex:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes-any": [
          "liquidity:write",
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "DeFindex"
        ]
      }
    },
    "/v1/defindex/vaults/{vault}/withdraw": {
      "post": {
        "description": "DeFindex builds the burn of `shares` (an integer string, at most 9007199254740991) for the vault's underlying assets, for `caller` on the key's network; `slippageBps` defaults to 100. The returned XDR is checked to be exactly that call and recorded for this key for up to 15 minutes (less if its time bounds close sooner): sign it unchanged and send it to `POST /v1/defindex/submit`.\n\nRequires the `liquidity:write` or `swaps:write` scope.",
        "operationId": "DefindexController_withdraw_v1",
        "parameters": [
          {
            "name": "vault",
            "required": true,
            "in": "path",
            "description": "The vault's contract address (C...).",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DefindexWithdrawDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DefindexBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Build an unsigned DeFindex share withdrawal",
        "tags": [
          "DeFindex"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "defindex:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes-any": [
          "liquidity:write",
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "DeFindex"
        ]
      }
    },
    "/v1/defindex/submit": {
      "post": {
        "description": "Relays `xdr` through DeFindex only when it is a signed copy of a transaction that `POST /v1/defindex/vaults/{vault}/deposit` or `/withdraw` built for this same API key on its network, before it expires; anything else is refused before DeFindex is called. Relayed once: DeFindex's answer is stored, and submitting the same transaction again answers it without calling DeFindex. When DeFindex gives no answer (502, 503) the same transaction may be submitted again.\n\nRequires the `liquidity:write` or `swaps:write` scope.",
        "operationId": "DefindexController_submit_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DefindexSubmitDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DefindexSubmitResultEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: the body fails validation, or `xdr` is not a transaction envelope, is a fee bump, or carries no signature. `invalid_state_transition`: the transaction expired before it was submitted; build a new one.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "xdr carries no signatures; sign the transaction before submitting it",
                      "path": "/v1/defindex/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "This DeFindex transaction expired before it was submitted and can no longer be relayed. Build a new one.",
                      "path": "/v1/defindex/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "No transaction built here for this API key on its network hashes to the signed one: it was changed after the build (anything but the signatures), built for another key or network, or never built here. The same answer for all of them.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No such resource, or it belongs to another consumer",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "This transaction was not built by POST /v1/defindex/vaults/{vault}/deposit or /withdraw for this API key on this network. Build it here, sign it unchanged, and submit it before it expires.",
                      "path": "/v1/defindex/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Another submit of the same transaction is waiting for DeFindex. Submit again once it finishes to read its stored answer.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "This DeFindex transaction is already being submitted. Wait for that submit to finish, then submit it again to read its result.",
                      "path": "/v1/defindex/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Submit a signed DeFindex transaction",
        "tags": [
          "DeFindex"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "defindex:submit",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes-any": [
          "liquidity:write",
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "DeFindex"
        ]
      }
    },
    "/v1/protected-payments": {
      "post": {
        "description": "Creates a protected payment in USDC on the key’s network, with the release model and the deadline policy of your choice, and answers `checkoutUrl`, the page to send the buyer. Nothing happens on-chain yet: the contract is deployed when the buyer first funds it. Emits `PROTECTED_PAYMENT_CREATED`; the same `Idempotency-Key` with the same request returns the stored payment.\n\nRequires the `payments:write` scope.",
        "operationId": "ProtectedPaymentsController_create_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional idempotency key. A retry with the same key and the same request returns the stored payment unchanged; the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "order-1042"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateProtectedPaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: the body fails validation, the buyer is the merchant, or a party is one of the platform accounts. `invalid_amount`: outside 1 to 1000000 USDC.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "amount must be from 1 to 1000000 USDC",
                      "path": "/v1/protected-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`idempotency_conflict`: This Idempotency-Key was already used for a different request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "This Idempotency-Key was already used for a different protected payment. Use a new key for a new request.",
                      "path": "/v1/protected-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "Protected payments are not configured on the key’s network, or the deadline policy needs a resolver this deployment does not have.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "REFUND_BUYER is not available on testnet: it needs the automatic resolver key, TRUSTLESS_WORK_RESOLVER_SECRET_TESTNET.",
                      "path": "/v1/protected-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Create a protected payment (the buyer pays into a contract until delivery)",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payments:create",
            "limit": 30,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      },
      "get": {
        "description": "Newest first, as `{ data, total, take, skip }` with `take` up to 100 (default 20). Only payments on the key’s network, narrowed by `status` when given, as this service last read them from their contracts.\n\nRequires the `payments:read` scope.",
        "operationId": "ProtectedPaymentsController_findAll_v1",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only protected payments in this status.",
            "schema": {
              "type": "string",
              "enum": [
                "CREATED",
                "AWAITING_FUNDING",
                "FUNDED",
                "SHIPPED",
                "APPROVED",
                "RELEASED",
                "DISPUTED",
                "RESOLVED",
                "EXPIRED",
                "CANCELLED"
              ]
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "How many to return per page (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many to skip before the page starts (newest first).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List your protected payments",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/protected-payments/{id}": {
      "get": {
        "description": "The payment as this service last read it from its contract (the sync job reads open contracts every 30 seconds), with its fees and `checkoutUrl`.\n\nRequires the `payments:read` scope.",
        "operationId": "ProtectedPaymentsController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get one of your protected payments",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/protected-payments/{id}/ship": {
      "post": {
        "description": "For a FUNDED payment: Trustless Work builds the milestone change to `shipped` with `evidence`, which this service checks is exactly that call and records for 15 minutes. Sign it with `merchantAddress` and send it to `POST /v1/protected-payments/submit`.\n\nRequires the `payments:write` scope.",
        "operationId": "ProtectedPaymentsController_ship_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ShipProtectedPaymentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: the payment is not in a state this action can be built from, or the release model gives it to the other party. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot ship a protected payment that is AWAITING_FUNDING.",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/ship",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "Trustless Work refused the request: amount must be a number",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/ship",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the merchant’s \"shipped\" mark, with tracking evidence",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payments:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ]
      }
    },
    "/v1/protected-payments/{id}/approve": {
      "post": {
        "description": "Only where the merchant is the approver (`MERCHANT_RELEASES`), for a FUNDED or SHIPPED payment. Answers the checked envelope for `merchantAddress` to sign and submit.\n\nRequires the `payments:write` scope.",
        "operationId": "ProtectedPaymentsController_approve_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: the payment is not in a state this action can be built from, or the release model gives it to the other party. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot approve a protected payment that is AWAITING_FUNDING.",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/approve",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "Trustless Work refused the request: amount must be a number",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/approve",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the merchant’s approval of delivery (MERCHANT_RELEASES)",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payments:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ]
      }
    },
    "/v1/protected-payments/{id}/release": {
      "post": {
        "description": "Where the merchant releases (`MERCHANT_RELEASES`, `BUYER_APPROVES_MERCHANT_RELEASES`), for an APPROVED payment. The contract pays the amount less 1.95% to `merchantAddress`. Answers the checked envelope to sign and submit.\n\nRequires the `payments:write` scope.",
        "operationId": "ProtectedPaymentsController_release_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: the payment is not in a state this action can be built from, or the release model gives it to the other party. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot release a protected payment that is AWAITING_FUNDING.",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/release",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "Trustless Work refused the request: amount must be a number",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/release",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the release of the funds to the merchant",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payments:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ]
      }
    },
    "/v1/protected-payments/{id}/dispute": {
      "post": {
        "description": "For a FUNDED, SHIPPED or APPROVED payment: answers the dispute for `merchantAddress` to sign and submit. `reason` is kept by this service only; Cosmos Pay ops (or the automatic resolver, under an auto deadline policy) then splits the balance between the buyer and the merchant.\n\nRequires the `payments:write` scope.",
        "operationId": "ProtectedPaymentsController_dispute_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DisputeProtectedPaymentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: the payment is not in a state this action can be built from, or the release model gives it to the other party. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot dispute a protected payment that is AWAITING_FUNDING.",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/dispute",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "Trustless Work refused the request: amount must be a number",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/dispute",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the merchant’s dispute",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payments:build",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ]
      }
    },
    "/v1/protected-payments/{id}/cancel": {
      "post": {
        "description": "Only CREATED, or AWAITING_FUNDING with an empty contract. Refused while a deposit the buyer was handed can still land (it lapses within 15 minutes). Emits `PROTECTED_PAYMENT_CANCELLED`.\n\nRequires the `payments:write` scope.",
        "operationId": "ProtectedPaymentsController_cancel_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentEntity"
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: The resource cannot move to that state from the one it is in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot cancel a protected payment that is FUNDED: only one nobody funded can be cancelled.",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/cancel",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "description": "`operation_in_flight`: A conflicting operation is still settling",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "The buyer holds a deposit for this protected payment that can still land. Retry once it expires (15 minutes at most).",
                      "path": "/v1/protected-payments/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/cancel",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Cancel a protected payment nobody funded",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ]
      }
    },
    "/v1/protected-payments/submit": {
      "post": {
        "description": "Relays `xdr` through Trustless Work only when it is a signed copy of a transaction built for that payment, for `merchantAddress`, on the key’s network, before it expires. Relayed once: the answer is stored and a replay returns it; on `SUCCESS` the payment moves and its webhook is emitted.\n\nRequires the `payments:write` scope.",
        "operationId": "ProtectedPaymentsController_submit_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitProtectedPaymentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentSubmitEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: `xdr` is not an envelope, is a fee bump or carries no signature. `invalid_state_transition`: it expired before it was submitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "xdr carries no signatures; sign the transaction before submitting it",
                      "path": "/v1/protected-payments/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "This protected payment transaction expired before it was submitted and can no longer be relayed. Build a new one.",
                      "path": "/v1/protected-payments/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`operation_in_flight`: A conflicting operation is still settling",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "This protected payment transaction is already being submitted. Wait for that submit to finish, then submit it again to read its result.",
                      "path": "/v1/protected-payments/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Submit a merchant-signed protected payment transaction",
        "tags": [
          "Protected payments"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payments:submit",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ]
      }
    },
    "/v1/protected-payment-links/{id}": {
      "get": {
        "description": "For the hosted checkout: the amount, the merchant, the release model, the deadlines, the status and `buyerActions`, what the buyer may do now. **The id is the capability**: nothing about the merchant’s account or `reference` is returned. Answered with `Cache-Control: no-store` and budgeted per client address.",
        "operationId": "ProtectedPaymentLinksController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The protected payment id (a uuid), as in the link `https://payments.cosmospay.lat/protected/<id>`.",
            "schema": {
              "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentLinkEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "404": {
            "description": "No protected payment has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No such resource, or it belongs to another consumer",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Protected payment 3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10 not found",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Read a protected payment as its buyer sees it (no API key)",
        "tags": [
          "Protected payment links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payment-links:read",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "security": []
      }
    },
    "/v1/protected-payment-links/{id}/fund": {
      "post": {
        "description": "The first call deploys the payment’s contract (Cosmos Pay pays for it) and binds `buyer`, once Horizon shows it holds the amount in USDC; a different buyer afterwards, or one the merchant did not name, is 409. Answers the checked deposit for `buyer` to sign and send to the link’s submit, before the funding window closes.",
        "operationId": "ProtectedPaymentLinksController_fund_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The protected payment id (a uuid), as in the link `https://payments.cosmospay.lat/protected/<id>`.",
            "schema": {
              "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FundProtectedPaymentLinkDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentLinkBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: `buyer` is the merchant, a platform account or an account that does not exist. `invalid_state_transition`: the payment is no longer open for funding. `trustline_missing`: the buyer does not trust USDC, or the merchant cannot receive it. `insufficient_balance`: the buyer holds less than the amount. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot fund a protected payment that is FUNDED.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/fund",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5, so it cannot receive the swap. Only that account can add the trustline, by signing a transaction of its own: ask its owner to add it, then try again.",
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "insufficient_balance": {
                    "summary": "insufficient_balance: The source account cannot cover the amount, or the XLM reserve the transaction needs",
                    "value": {
                      "statusCode": 400,
                      "code": "insufficient_balance",
                      "error": "Bad Request",
                      "message": "Account GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76 holds 20 USDC; this protected payment takes 125.5.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/fund",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The payment provider rejected the request.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No protected payment has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No such resource, or it belongs to another consumer",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Protected payment 3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10 not found",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/fund",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`protected_payment_buyer_mismatch`: another buyer is bound. `operation_in_flight`: the contract is being deployed by another request; retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "protected_payment_buyer_mismatch": {
                    "summary": "protected_payment_buyer_mismatch: The protected payment is bound to another buyer",
                    "value": {
                      "statusCode": 409,
                      "code": "protected_payment_buyer_mismatch",
                      "error": "Conflict",
                      "message": "This protected payment is bound to another buyer: only GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76 may fund it.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/fund",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "This protected payment is being deployed by another request. Retry in a few seconds.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/fund",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the buyer’s deposit into the protected payment (no API key)",
        "tags": [
          "Protected payment links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payment-links:build",
            "limit": 10,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Horizon",
          "Trustless Work"
        ],
        "security": []
      }
    },
    "/v1/protected-payment-links/{id}/approve": {
      "post": {
        "description": "Where the buyer approves (`BUYER_RELEASES`, `BUYER_APPROVES_MERCHANT_RELEASES`), for a FUNDED or SHIPPED payment. Answers the checked envelope for the bound buyer to sign and send to the link’s submit.",
        "operationId": "ProtectedPaymentLinksController_approve_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The protected payment id (a uuid), as in the link `https://payments.cosmospay.lat/protected/<id>`.",
            "schema": {
              "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentLinkBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: the payment is not in a state this action can be built from, or the release model gives it to the merchant. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot approve a protected payment that is RELEASED.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/approve",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "Trustless Work refused the request: amount must be a number",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/approve",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No protected payment has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No such resource, or it belongs to another consumer",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Protected payment 3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10 not found",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/approve",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the buyer’s confirmation of delivery (no API key)",
        "tags": [
          "Protected payment links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payment-links:build",
            "limit": 10,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ],
        "security": []
      }
    },
    "/v1/protected-payment-links/{id}/release": {
      "post": {
        "description": "Only under `BUYER_RELEASES`, for an APPROVED payment: the contract pays the merchant the amount less 1.95%. Answers the checked envelope for the bound buyer to sign and send to the link’s submit.",
        "operationId": "ProtectedPaymentLinksController_release_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The protected payment id (a uuid), as in the link `https://payments.cosmospay.lat/protected/<id>`.",
            "schema": {
              "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentLinkBuildEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: the payment is not in a state this action can be built from, or the release model gives it to the merchant. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot release a protected payment that is RELEASED.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/release",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "Trustless Work refused the request: amount must be a number",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/release",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No protected payment has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No such resource, or it belongs to another consumer",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Protected payment 3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10 not found",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/release",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Build the buyer’s release of the funds (no API key)",
        "tags": [
          "Protected payment links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payment-links:build",
            "limit": 10,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ],
        "security": []
      }
    },
    "/v1/protected-payment-links/{id}/dispute": {
      "post": {
        "description": "Where the buyer holds a role in the contract, answers `built`, the dispute for the buyer to sign and submit. Under `MERCHANT_RELEASES` the buyer holds none, so Cosmos Pay’s platform key opens it (`submitted`) once `signature` proves the buyer signed the link’s `disputeChallenge` before `expiresAt`.",
        "operationId": "ProtectedPaymentLinksController_dispute_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The protected payment id (a uuid), as in the link `https://payments.cosmospay.lat/protected/<id>`.",
            "schema": {
              "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DisputeProtectedPaymentLinkDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentLinkDisputeEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_state_transition`: the payment is not funded, or already settled. `protected_payment_signature_invalid`: the signed message is missing, does not verify against the buyer, or expired. `provider_error`: Trustless Work refused the request.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot dispute a protected payment that is RELEASED.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/dispute",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "protected_payment_signature_invalid": {
                    "summary": "protected_payment_signature_invalid: The buyer's signed message does not verify, or it expired",
                    "value": {
                      "statusCode": 400,
                      "code": "protected_payment_signature_invalid",
                      "error": "Bad Request",
                      "message": "The signature does not verify against the payment's buyer address.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/dispute",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The payment provider rejected the request.",
                      "path": "/v1/onramp/quotes",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No protected payment has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No such resource, or it belongs to another consumer",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Protected payment 3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10 not found",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/dispute",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Open the buyer’s dispute (no API key)",
        "tags": [
          "Protected payment links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payment-links:build",
            "limit": 10,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ],
        "security": []
      }
    },
    "/v1/protected-payment-links/{id}/submit": {
      "post": {
        "description": "Relays `xdr` through Trustless Work only when it is a signed copy of a transaction this link built for the bound buyer, before it expires. Relayed once: the answer is stored and a replay returns it; on `SUCCESS` the payment moves.",
        "operationId": "ProtectedPaymentLinksController_submit_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The protected payment id (a uuid), as in the link `https://payments.cosmospay.lat/protected/<id>`.",
            "schema": {
              "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitProtectedPaymentLinkDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ProtectedPaymentLinkSubmitEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: `xdr` is not an envelope, is a fee bump or carries no signature. `invalid_state_transition`: it expired before it was submitted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "xdr carries no signatures; sign the transaction before submitting it",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "This protected payment transaction expired before it was submitted and can no longer be relayed. Build a new one.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No protected payment has this id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No such resource, or it belongs to another consumer",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Protected payment 3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10 not found",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`operation_in_flight`: A conflicting operation is still settling",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "This protected payment transaction is already being submitted. Wait for that submit to finish, then submit it again to read its result.",
                      "path": "/v1/protected-payment-links/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "$ref": "#/components/responses/UpstreamError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          },
          "504": {
            "$ref": "#/components/responses/UpstreamTimeout"
          }
        },
        "summary": "Submit a buyer-signed protected payment transaction (no API key)",
        "tags": [
          "Protected payment links"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "protected-payment-links:submit",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Trustless Work"
        ],
        "security": []
      }
    },
    "/v1/zk-payments/config": {
      "get": {
        "description": "What a dashboard needs to set a merchant up on the confidential token (register, read the balance, withdraw). `enabled` is false on a network where private payments do not run yet (mainnet today). The same shape as the keyless `GET /v1/zk-checkout/config?network=`.\n\nRequires the `payments:read` scope.",
        "operationId": "ZkPaymentsController_getConfig_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZkPaymentsConfigEntity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "The private payments setup of the API key's network",
        "tags": [
          "zk-payments"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/zk-payments": {
      "post": {
        "description": "A private payment hides its amount on-chain: it is paid with confidential transfers on Cosmos Pay's confidential token, proven with zero-knowledge proofs (hence `zk` in the paths). Prices the payment (`amount` = `netAmount` + `feeAmount`, the fee rounded up and at least one stroop) and checks on-chain that the recipient holds a confidential account on the token under auditor 0. The payer then makes two confidential transfers (net to the merchant, fee to the fee account) and confirms them at `POST /v1/zk-checkout/{id}/confirm`. With a `merchantFee`, a third transfer pays it to its wallet, which must hold a confidential account on the token too.\n\nRequires the `payments:write` scope.",
        "operationId": "ZkPaymentsController_create_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional idempotency key. A retry with the same key and the same request returns the existing payment; the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "order-24"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateZkPaymentDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZkPaymentEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`invalid_amount`: after the commission (and the merchant fee) the merchant would receive nothing, or the merchant fee rounds to nothing. `recipient_not_registered`: the recipient, or the merchant fee's wallet, has no confidential account on the token under auditor 0. `network_unsupported`: private payments do not run on this network yet (mainnet today; use a dev key).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: The merchant would receive nothing after the commission",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "The amount is too small: after the 0.18% commission (at least one stroop) the merchant would receive nothing.",
                      "path": "/v1/zk-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "recipient_not_registered": {
                    "summary": "recipient_not_registered: The recipient holds no confidential account on Cosmos Pay's token under auditor 0",
                    "value": {
                      "statusCode": 400,
                      "code": "recipient_not_registered",
                      "error": "Bad Request",
                      "message": "The recipient GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO is not registered on Cosmos Pay's confidential token. Register it with the wallet first, under auditor id 0.",
                      "path": "/v1/zk-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: Private payments do not run on this network yet (mainnet today)",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "Private payments are not available on public yet. They run on testnet only for now: use a dev API key.",
                      "path": "/v1/zk-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "`idempotency_conflict`: this key was already used for a different payment. `operation_in_flight`: a concurrent create with the same key changed it while this one ran; retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "A private payment with this idempotency key already exists for a different request. Retry with the original request unchanged, or use a new key.",
                      "path": "/v1/zk-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "operation_in_flight": {
                    "summary": "operation_in_flight: A conflicting operation is still settling",
                    "value": {
                      "statusCode": 409,
                      "code": "operation_in_flight",
                      "error": "Conflict",
                      "message": "A concurrent request for this idempotency key changed it while this one was being created. Retry the request.",
                      "path": "/v1/zk-payments",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Create a private payment (0.18% commission)",
        "tags": [
          "zk-payments"
        ],
        "x-cosmos-rate-limit": [
          {
            "name": "zk-payments:create",
            "limit": 30,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ],
        "x-cosmos-upstream": [
          "Soroban RPC"
        ]
      },
      "get": {
        "description": "Newest first, optionally filtered by `status` as it reads now (a `PENDING` payment past `expiresAt` reads, and filters, as `EXPIRED`). Paginated with `take` (default 20, max 100) and `skip`; the answer is `{ data, total, take, skip }`. Only payments on the key's network are listed (a `prod` key sees mainnet, a `dev` key testnet).\n\nRequires the `payments:read` scope.",
        "operationId": "ZkPaymentsController_findAll_v1",
        "parameters": [
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "Page size: how many items to return (1 to 100).",
            "schema": {
              "minimum": 1,
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many items to skip before this page (offset).",
            "schema": {
              "minimum": 0,
              "default": 0,
              "type": "number"
            }
          },
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only payments in this status, as it reads now: `EXPIRED` includes a PENDING payment past `expiresAt`, and `PENDING` excludes one.",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "SUCCEEDED",
                "EXPIRED"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZkPaymentListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's private payments",
        "tags": [
          "zk-payments"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/zk-payments/{id}": {
      "get": {
        "description": "One of your private payments: its amounts (`amount`, `netAmount`, `feeAmount`), recipient, payer and the hashes of the transfers that settled it. `status` reads as it is now: a `PENDING` payment past `expiresAt` reads `EXPIRED`, and can still settle with transfers that closed in time. The payer's view of it is the keyless `GET /v1/zk-checkout/{id}`.\n\nRequires the `payments:read` scope.",
        "operationId": "ZkPaymentsController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZkPaymentEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a private payment by id",
        "tags": [
          "zk-payments"
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/zk-checkout/config": {
      "get": {
        "description": "The same shape as `GET /v1/zk-payments/config`, built by the same code, for a page with no API key: the merchant's confidential-account page (register, balance, withdraw) and the checkout read the contracts they prove against here. Everything in it is public on-chain data. `enabled` is false, and the rest null, on a network where private payments do not run yet (mainnet today).",
        "operationId": "ZkCheckoutController_config_v1",
        "parameters": [
          {
            "name": "network",
            "required": true,
            "in": "query",
            "description": "The network to describe. Named by the caller, since a keyless page has no API key to take it from.",
            "schema": {
              "example": "testnet",
              "type": "string",
              "enum": [
                "testnet",
                "public"
              ]
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ZkPaymentsConfigEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "A network's private payments setup, keyless: token, registries, auditor id, commission, fee account",
        "tags": [
          "zk-checkout"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "zk-payments:public-read",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "security": []
      }
    },
    "/v1/zk-checkout/{id}": {
      "get": {
        "description": "For a checkout: the gross amount, the net and the commission, the merchant and the fee account to transfer to, the token and the RPC to prove and submit with, and the live status to poll.\n\n**The id is the capability.** Nothing about the owning merchant account, the idempotency key or the settling transactions is returned.",
        "operationId": "ZkCheckoutController_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The private payment id (a cuid), as the merchant shared it.",
            "schema": {
              "example": "cmh4x2k9a0001l70g8v5q3z2w",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              },
              "Cache-Control": {
                "description": "Always `no-store`: the status changes live.",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              }
            },
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicZkPaymentEntity"
                }
              }
            }
          },
          "400": {
            "description": "`network_unsupported`: the payment's network or token is no longer served by this deployment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "network_unsupported": {
                    "summary": "network_unsupported: The payment's network no longer runs private payments here",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "Private payments are not available on public yet. They run on testnet only for now: use a dev API key.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No private payment has this id. The same answer the owner gets from `GET /v1/zk-payments/{id}` for one that never existed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No private payment has this id",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Private payment cmh4x2k9a0001l70g8v5q3z2w not found",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Read a private payment as its payer sees it (no API key)",
        "tags": [
          "zk-checkout"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "zk-payments:public-read",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "security": []
      }
    },
    "/v1/zk-checkout/{id}/confirm": {
      "post": {
        "description": "Reads both transactions back through the Soroban RPC and settles the payment only when: both succeeded and each is a single `confidential_transfer` on the token; both closed while the payment was open (not before it was created, not after `expiresAt`); both come from the same payer; the payment transfer goes to the recipient and the fee transfer to the fee account; and each decrypts with the auditor key, on both auditor channels and against the transfer's commitment, to exactly `netAmount` / `feeAmount`. Neither transaction may have settled another private payment.\n\nIdempotent: the same hashes on a settled payment answer it again. A refusal leaves the payment PENDING, and never says what an amount decrypted to.\n\nA payment with a `merchantFee` has a third transfer, of `merchantFee.amount` to `merchantFee.wallet`: send its hash as `merchantFeeTxHash` (required for such a payment, refused for any other). It is checked like the other two, in the same order.",
        "operationId": "ZkCheckoutController_confirm_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The private payment id (a cuid), as the merchant shared it.",
            "schema": {
              "example": "cmh4x2k9a0001l70g8v5q3z2w",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ConfirmZkPaymentDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              },
              "Cache-Control": {
                "description": "Always `no-store`: the status changes live.",
                "schema": {
                  "type": "string",
                  "example": "no-store"
                }
              }
            },
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicZkPaymentEntity"
                }
              }
            }
          },
          "400": {
            "description": "`transaction_not_found`: the RPC has no such transaction yet (retry in a few seconds) or no longer. `transaction_rejected`: it failed on-chain. `payment_transfer_mismatch` / `fee_transfer_mismatch` / `merchant_fee_transfer_mismatch`: that transaction is not the confidential transfer this payment needs (wrong token, shape, recipient, amount, or it closed before the payment existed). `payer_mismatch`: the transfers come from different accounts. `expired`: a transfer closed after `expiresAt`. `invalid_state_transition`: already settled by other transactions. `validation_failed` also answers a `merchantFeeTxHash` missing on a payment with a merchant fee, or sent for one without.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": [
                        "amount must be a positive decimal string",
                        "destination must be a valid Stellar public key"
                      ],
                      "path": "/v1/swaps",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "transaction_not_found": {
                    "summary": "transaction_not_found: No such transaction on the network yet, or it is older than the RPC keeps",
                    "value": {
                      "statusCode": 400,
                      "code": "transaction_not_found",
                      "error": "Bad Request",
                      "message": "Transaction 5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a was not found on testnet: it has not closed yet, or it is older than the RPC keeps. Retry in a few seconds.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "transaction_rejected": {
                    "summary": "transaction_rejected: The transaction failed on-chain",
                    "value": {
                      "statusCode": 400,
                      "code": "transaction_rejected",
                      "error": "Bad Request",
                      "message": "The payment transaction 5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a failed on-chain and moved nothing.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "payment_transfer_mismatch": {
                    "summary": "payment_transfer_mismatch: The payment transaction does not pay this payment's net amount to its recipient",
                    "value": {
                      "statusCode": 400,
                      "code": "payment_transfer_mismatch",
                      "error": "Bad Request",
                      "message": "The payment transaction does not settle this private payment: it is not a confidential transfer of the payment's net amount to its recipient.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "fee_transfer_mismatch": {
                    "summary": "fee_transfer_mismatch: The fee transaction does not pay this payment's commission to the fee account",
                    "value": {
                      "statusCode": 400,
                      "code": "fee_transfer_mismatch",
                      "error": "Bad Request",
                      "message": "The fee transaction does not settle this private payment: it is not a confidential transfer of the commission to the fee account.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "merchant_fee_transfer_mismatch": {
                    "summary": "merchant_fee_transfer_mismatch: The merchant fee transaction does not pay this payment's merchant fee to its wallet",
                    "value": {
                      "statusCode": 400,
                      "code": "merchant_fee_transfer_mismatch",
                      "error": "Bad Request",
                      "message": "The merchant fee transaction does not settle this private payment: it is not a confidential transfer of the merchant fee to the fee's wallet.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "payer_mismatch": {
                    "summary": "payer_mismatch: The payment and fee transfers come from different accounts",
                    "value": {
                      "statusCode": 400,
                      "code": "payer_mismatch",
                      "error": "Bad Request",
                      "message": "The payment and fee transfers must come from the same account; they come from two different ones.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "expired": {
                    "summary": "expired: A transfer of the private payment closed after the payment expired",
                    "value": {
                      "statusCode": 400,
                      "code": "expired",
                      "error": "Bad Request",
                      "message": "The payment transaction closed at 2026-10-25T14:05:12.000Z, after this Private payment expired at 2026-10-25T14:00:00.000Z.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: Already settled, by other transactions",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "This private payment is already settled, by other transactions.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: The payment's network no longer runs private payments here",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "Private payments are not available on public yet. They run on testnet only for now: use a dev API key.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No private payment has this id. The same answer the owner gets from `GET /v1/zk-payments/{id}` for one that never existed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "not_found": {
                    "summary": "not_found: No private payment has this id",
                    "value": {
                      "statusCode": 404,
                      "code": "not_found",
                      "error": "Not Found",
                      "message": "Private payment cmh4x2k9a0001l70g8v5q3z2w not found",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`transaction_already_settled`: one of the transactions already settled another private payment, of any merchant. One transaction settles at most one payment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "transaction_already_settled": {
                    "summary": "transaction_already_settled: A transaction already settled another private payment",
                    "value": {
                      "statusCode": 409,
                      "code": "transaction_already_settled",
                      "error": "Conflict",
                      "message": "One of these transactions already settled another private payment. One transaction settles at most one payment.",
                      "path": "/v1/zk-checkout/cmh4x2k9a0001l70g8v5q3z2w/confirm",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "$ref": "#/components/responses/UpstreamUnavailable"
          }
        },
        "summary": "Confirm a private payment with its confidential transfers, verified on-chain (no API key)",
        "tags": [
          "zk-checkout"
        ],
        "x-cosmos-public": true,
        "x-cosmos-rate-limit": [
          {
            "name": "zk-payments:confirm",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-upstream": [
          "Soroban RPC"
        ],
        "security": []
      }
    },
    "/v1/usdt0/routes": {
      "get": {
        "description": "USDT0 is Tether’s omnichain USDT. From Stellar it travels through LayerZero’s OFT: Ethereum receives native USDT (Tether’s OFT adapter unlocks it), every other network receives USDT0. All routes take an EVM recipient. USDT0 exists on Stellar mainnet only: a dev (testnet) key gets `available: false` and no routes.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "Usdt0Controller_routes_v1",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usdt0RoutesEntity"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "The networks USDT0 can be sent to from Stellar, with what arrives there (mainnet only)",
        "tags": [
          "usdt0"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "swaps:read"
        ]
      }
    },
    "/v1/usdt0/quote": {
      "post": {
        "description": "Simulates the OFT’s `quote_oft` and `quote_send` on Stellar mainnet. The OFT carries 6 decimals and the asset has 7, so the 7th is `dust` that stays in the account. `nativeFee` is LayerZero’s fee, paid in XLM on top of the USDT0; `nativeFeeLimit` is what a transfer built now would offer (20% more, the excess refunded in the same transaction). Mainnet only.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "Usdt0Controller_quote_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QuoteUsdt0Dto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usdt0QuoteEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`network_unsupported`: a dev (testnet) key; USDT0 is on Stellar mainnet only. `invalid_amount`: less than 0.000001 USDT0 (all dust), or outside the OFT’s limits. `provider_error`: the OFT refused the quote; `message` carries its contract error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "amount must be at least 0.000001 USDT0: the OFT carries 6 decimals, and the 7th stays in the account as dust",
                      "path": "/v1/usdt0/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: USDT0 is on Stellar mainnet only; a dev key cannot use this route",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "USDT0 is on Stellar mainnet only: it does not exist on Stellar testnet. Use a prod API key.",
                      "path": "/v1/usdt0/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The USDT0 contract refused the quote (quote_send): HostError: Error(Contract, #2001)",
                      "path": "/v1/usdt0/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "`provider_error`: the Soroban RPC answered the simulation with no result, or in a shape the OFT never returns.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 502,
                      "code": "provider_error",
                      "error": "Bad Gateway",
                      "message": "The USDT0 contract answered quote_oft in an unexpected shape.",
                      "path": "/v1/usdt0/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`provider_unavailable`: the Soroban RPC did not answer; retry. `misconfigured`: STELLAR_RPC_URL_MAINNET serves another network, or USDT0_FEE_WRAPPER is set with a plan commission and no STELLAR_SWAP_FEE_WALLET.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "The Stellar mainnet Soroban RPC is unavailable. Retry shortly.",
                      "path": "/v1/usdt0/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "The Soroban RPC configured for Stellar mainnet (STELLAR_RPC_URL_MAINNET) serves another network.",
                      "path": "/v1/usdt0/quote",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Quote a USDT0 transfer from Stellar; persists nothing",
        "tags": [
          "usdt0"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "usdt0:quote",
            "limit": 60,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:read"
        ],
        "x-cosmos-upstream": [
          "Soroban RPC"
        ]
      }
    },
    "/v1/usdt0/transfers": {
      "post": {
        "description": "Builds `send` on USDT0’s LayerZero OFT: it burns the USDT0 on Stellar and LayerZero delivers it to `recipient`, as native USDT on Ethereum and as USDT0 elsewhere. The source signs one transaction (Freighter, or the SEP-7 `uri`) and pays two fees in XLM: LayerZero’s (`nativeFeeLimit` is offered, the unused part refunded in the same transaction) and the network’s (`networkFee`). A 7th decimal of `amount` is `dust` and stays in the account. No Cosmos Pay commission is charged. Mainnet only. Submit the signed XDR to `POST /v1/usdt0/transfers/{id}/submit`, then follow `GET /v1/usdt0/transfers/{id}`.\n\nRequires the `swaps:write` scope. The shared public key may call it.",
        "operationId": "Usdt0Controller_create_v1",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "description": "Optional idempotency key. A retry with the same key and the same request returns the stored transfer unchanged; the same key with a different request is 409 idempotency_conflict. Takes precedence over body.idempotencyKey.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "usdt0-retry-2026-10-25-001"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateUsdt0TransferDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The transfer. With the shared public key it carries `publicToken`: send it as `X-Record-Token` to read the transfer or submit it.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usdt0TransferCreatedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`merchant_fee_unsupported`: a `merchantFee` and no merchant fee wrapper configured (USDT0_FEE_WRAPPER). `network_unsupported`: a dev (testnet) key; USDT0 is on Stellar mainnet only. `validation_failed`: the source account does not exist, or the recipient has a bad EIP-55 checksum. `trustline_missing`: the source does not trust USDT0. `insufficient_balance`: it holds less USDT0 than the transfer takes, or too little XLM for LayerZero’s fee limit, the network fee and its reserve (the message says how much XLM to add). `invalid_amount`: all dust, or outside the OFT’s limits. `provider_error`: the OFT refused the transfer; `message` carries its contract error. With a merchant fee, `trustline_missing` also answers a fee wallet that does not trust USDT0, and `insufficient_balance` counts the fee the holder pays on top.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "recipient has an invalid EIP-55 checksum: check the address, or send it in lowercase",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_amount": {
                    "summary": "invalid_amount: Not a Stellar amount, or not greater than zero",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_amount",
                      "error": "Bad Request",
                      "message": "amount must be at least 0.000001 USDT0: the OFT carries 6 decimals, and the 7th stays in the account as dust",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "trustline_missing": {
                    "summary": "trustline_missing: An account does not trust the asset, and this request cannot add the trustline for it",
                    "value": {
                      "statusCode": 400,
                      "code": "trustline_missing",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ has no trustline for USDT0:GATISXX6BZ6NC7IKQBY37CJD4SOZL3CYZJWXEDG6JVIY4WBS6KXJHN6Q, so it holds no USDT0 to send. Add the trustline and receive USDT0 first, then try again.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "insufficient_balance": {
                    "summary": "insufficient_balance: The source account cannot cover the amount, or the XLM reserve the transaction needs",
                    "value": {
                      "statusCode": 400,
                      "code": "insufficient_balance",
                      "error": "Bad Request",
                      "message": "Account GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ cannot pay this transfer's fees in XLM: it needs 7.1996499 XLM (its minimum balance of 1.5 XLM, the 4.2474009 XLM LayerZero fee limit, the 1.452249 XLM network fee) but holds 5 XLM. Add at least 2.1996499 XLM to it, then try again. What LayerZero does not charge of its fee limit comes back in the same transaction.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: USDT0 is on Stellar mainnet only; a dev key cannot use this route",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "USDT0 is on Stellar mainnet only: it does not exist on Stellar testnet. Use a prod API key.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 400,
                      "code": "provider_error",
                      "error": "Bad Request",
                      "message": "The USDT0 contract refused the transfer: HostError: Error(Contract, #2001)",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "merchant_fee_unsupported": {
                    "summary": "merchant_fee_unsupported: This operation cannot pay a merchant fee yet",
                    "value": {
                      "statusCode": 400,
                      "code": "merchant_fee_unsupported",
                      "error": "Bad Request",
                      "message": "A merchant fee is not available on USDT0 transfers on this deployment: a Soroban transaction carries one operation, so the fee needs the fee wrapper (USDT0_FEE_WRAPPER), which is not configured.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "description": "This Idempotency-Key was already used for a different USDT0 transfer request, or an identical transfer was built from the same account in the same second.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "idempotency_conflict": {
                    "summary": "idempotency_conflict: This Idempotency-Key was already used for a different request",
                    "value": {
                      "statusCode": 409,
                      "code": "idempotency_conflict",
                      "error": "Conflict",
                      "message": "This Idempotency-Key was already used for a different USDT0 transfer request. Use a new key for a new request.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "502": {
            "description": "`provider_error`: the OFT cannot be called right now (part of its state is archived on the ledger, or it asks for a signature the transaction cannot carry), or the RPC answered in an unexpected shape.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_error": {
                    "summary": "provider_error: The upstream provider refused the request",
                    "value": {
                      "statusCode": 502,
                      "code": "provider_error",
                      "error": "Bad Gateway",
                      "message": "Part of the USDT0 contract state is archived on the ledger and must be restored before a transfer can be built. Retry later.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "`provider_unavailable`: Horizon or the Soroban RPC did not answer; retry. `misconfigured`: STELLAR_RPC_URL_MAINNET serves another network, or USDT0_FEE_WRAPPER is not the reviewed wrapper bound to USDT0's OFT and token, or the plan commission has no STELLAR_SWAP_FEE_WALLET, or one that does not trust USDT0.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "The Stellar mainnet Soroban RPC is unavailable. Retry shortly.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "The Soroban RPC configured for Stellar mainnet (STELLAR_RPC_URL_MAINNET) serves another network.",
                      "path": "/v1/usdt0/transfers",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Create a USDT0 transfer from Stellar → the unsigned Soroban transaction to sign (XDR + SEP-7 link)",
        "tags": [
          "usdt0"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "usdt0:create",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "Horizon",
          "Soroban RPC"
        ]
      },
      "get": {
        "description": "Answers from this service’s own table, as last refreshed; read one transfer to refresh it. Refused to the shared public key, which is every anonymous caller at once.\n\nRequires the `swaps:read` scope.",
        "operationId": "Usdt0Controller_findAll_v1",
        "parameters": [
          {
            "name": "status",
            "required": false,
            "in": "query",
            "description": "Only transfers in this status, as last refreshed.",
            "schema": {
              "type": "string",
              "enum": [
                "PENDING",
                "SUBMITTED",
                "DELIVERED",
                "FAILED",
                "EXPIRED"
              ]
            }
          },
          {
            "name": "take",
            "required": false,
            "in": "query",
            "description": "How many transfers to return per page (1 to 100).",
            "schema": {
              "maximum": 100,
              "default": 20,
              "type": "number"
            }
          },
          {
            "name": "skip",
            "required": false,
            "in": "query",
            "description": "How many matching transfers to skip before the page starts (newest first).",
            "schema": {
              "default": 0,
              "type": "number"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usdt0TransferListEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "List the consumer's USDT0 transfers (not on the shared public key)",
        "tags": [
          "usdt0"
        ],
        "x-cosmos-scopes": [
          "swaps:read"
        ]
      }
    },
    "/v1/usdt0/transfers/{id}": {
      "get": {
        "description": "While PENDING or SUBMITTED, a read asks the Stellar ledger (a wallet may have broadcast the transaction itself) and LayerZero Scan, at most once every 15 seconds per transfer, and moves it to SUBMITTED, DELIVERED (with `destinationTxHash`), FAILED or EXPIRED. Delivery takes about 27 minutes on every route: LayerZero’s verifiers wait for Stellar confirmations. The shared public key may call it, but only with the transfer’s `publicToken` in `X-Record-Token`: without it, or with another transfer’s, the answer is 404. Every other key reads its own transfers as before.\n\nRequires the `swaps:read` scope. The shared public key may call it.",
        "operationId": "Usdt0Controller_findOne_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Record-Token",
            "in": "header",
            "description": "Required with the shared public key: the `publicToken` the create response returned for this record. Without it, or with the token of another record, the answer is 404, as for a record that does not exist. Ignored for every other API key.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usdt0TransferEntity"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Get a USDT0 transfer by id, refreshed from the Stellar ledger and LayerZero Scan",
        "tags": [
          "usdt0"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-scopes": [
          "swaps:read"
        ]
      }
    },
    "/v1/usdt0/transfers/{id}/submit": {
      "post": {
        "description": "The signed XDR must hash to the transfer’s transaction and carry a signature. Accepted and applied: SUBMITTED, with LayerZero’s `guid`. Applied and failed: FAILED. Refused by the network: the transfer stays PENDING (`submitted: false`, `reason`) and can be submitted again until it expires. Waits up to 30 seconds for the ledger.\n\nRequires the `swaps:write` scope. The shared public key may call it.",
        "operationId": "Usdt0Controller_submit_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-Record-Token",
            "in": "header",
            "description": "Required with the shared public key: the `publicToken` the create response returned for this record. Without it, or with the token of another record, the answer is 404, as for a record that does not exist. Ignored for every other API key.",
            "required": false,
            "schema": {
              "type": "string",
              "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SubmitUsdt0TransferDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Usdt0SubmitResultEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "description": "`validation_failed`: `signedXdr` is not a transaction, is not the one built for this transfer, or carries no signature. `invalid_state_transition`: the transfer is FAILED or EXPIRED, or its transaction expired; build a new one. `network_unsupported`: a dev (testnet) key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "validation_failed": {
                    "summary": "validation_failed: The body, query or headers failed validation",
                    "value": {
                      "statusCode": 400,
                      "code": "validation_failed",
                      "error": "Bad Request",
                      "message": "The signed transaction does not match this transfer",
                      "path": "/v1/usdt0/transfers/cm2u0t0transfer0000000001/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "invalid_state_transition": {
                    "summary": "invalid_state_transition: The resource cannot move to that state from the one it is in",
                    "value": {
                      "statusCode": 400,
                      "code": "invalid_state_transition",
                      "error": "Bad Request",
                      "message": "Cannot submit a FAILED USDT0 transfer. Build a new one.",
                      "path": "/v1/usdt0/transfers/cm2u0t0transfer0000000001/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "network_unsupported": {
                    "summary": "network_unsupported: USDT0 is on Stellar mainnet only; a dev key cannot use this route",
                    "value": {
                      "statusCode": 400,
                      "code": "network_unsupported",
                      "error": "Bad Request",
                      "message": "USDT0 is on Stellar mainnet only: it does not exist on Stellar testnet. Use a prod API key.",
                      "path": "/v1/usdt0/transfers/cm2u0t0transfer0000000001/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          },
          "503": {
            "description": "`provider_unavailable`: the Soroban RPC did not answer, or the network asked to try again later; the transfer stays PENDING, submit again. `misconfigured`: STELLAR_RPC_URL_MAINNET serves another network.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "provider_unavailable": {
                    "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                    "value": {
                      "statusCode": 503,
                      "code": "provider_unavailable",
                      "error": "Service Unavailable",
                      "message": "The Stellar mainnet Soroban RPC is unavailable. Retry shortly.",
                      "path": "/v1/usdt0/transfers/cm2u0t0transfer0000000001/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  },
                  "misconfigured": {
                    "summary": "misconfigured: A server-side configuration error: retrying will not help",
                    "value": {
                      "statusCode": 503,
                      "code": "misconfigured",
                      "error": "Service Unavailable",
                      "message": "The Soroban RPC configured for Stellar mainnet (STELLAR_RPC_URL_MAINNET) serves another network.",
                      "path": "/v1/usdt0/transfers/cm2u0t0transfer0000000001/submit",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          }
        },
        "summary": "Relay the signed USDT0 transaction to Stellar mainnet",
        "tags": [
          "usdt0"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "usdt0:submit",
            "limit": 20,
            "windowMs": 60000
          }
        ],
        "x-cosmos-scopes": [
          "swaps:write"
        ],
        "x-cosmos-upstream": [
          "Soroban RPC"
        ]
      }
    },
    "/v1/wallet/easy-recovery/sessions": {
      "post": {
        "description": "Send a fresh X25519 public key; keep its private half on the device. Show a QR with the returned `id` and that key: nothing else, no secret and no server URL. The session lives five minutes.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "EasyRecoveryController_createSession_v1",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEasyRecoverySessionDto"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EasyRecoverySessionCreatedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Open a session on the new device",
        "tags": [
          "wallet-easy-recovery"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "easy-recovery-create",
            "limit": 20,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/wallet/easy-recovery/sessions/{id}": {
      "get": {
        "description": "Both devices poll it: the new one waits for `offered` to ask for the code, the old one for `claimed` to stop showing it. Answers the status and the expiry only, never the key, the sealed wallet or the code. An unknown, expired or burned session is a 404.\n\nRequires the `payments:read` scope. The shared public key may call it.",
        "operationId": "EasyRecoveryController_status_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The session id from `POST /v1/wallet/easy-recovery/sessions`, as the QR carries it: 22 base64url characters.",
            "schema": {
              "example": "q2Z7rT0aV1bX9cD4eF6gHw",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EasyRecoverySessionStatusEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "`easy_recovery_not_found`: No such session, or it expired, was claimed or was burned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "easy_recovery_not_found": {
                    "summary": "easy_recovery_not_found: No such session, or it expired, was claimed or was burned",
                    "value": {
                      "statusCode": 404,
                      "code": "easy_recovery_not_found",
                      "error": "Not Found",
                      "message": "This recovery session does not exist or has expired. Start again on the new device.",
                      "path": "/v1/wallet/easy-recovery/sessions/q2Z7rT0aV1bX9cD4eF6gHw",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Poll a session",
        "tags": [
          "wallet-easy-recovery"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "easy-recovery-poll",
            "limit": 600,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:read"
        ]
      }
    },
    "/v1/wallet/easy-recovery/sessions/{id}/offer": {
      "post": {
        "description": "After the person confirmed and unlocked on the old device: seal the wallet to the `receiverKey` read from the QR (ECIES, on the device), generate a random five-digit code, send both here and show the code. Accepted once per session, while it is `open`: the first offer wins and any later one is a 409. Only a hash of the code is stored.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "EasyRecoveryController_offer_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The session id from `POST /v1/wallet/easy-recovery/sessions`, as the QR carries it: 22 base64url characters.",
            "schema": {
              "example": "q2Z7rT0aV1bX9cD4eF6gHw",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/OfferEasyRecoveryDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EasyRecoveryOfferedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "`easy_recovery_not_found`: No such session, or it expired, was claimed or was burned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "easy_recovery_not_found": {
                    "summary": "easy_recovery_not_found: No such session, or it expired, was claimed or was burned",
                    "value": {
                      "statusCode": 404,
                      "code": "easy_recovery_not_found",
                      "error": "Not Found",
                      "message": "This recovery session does not exist or has expired. Start again on the new device.",
                      "path": "/v1/wallet/easy-recovery/sessions/q2Z7rT0aV1bX9cD4eF6gHw/offer",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`easy_recovery_already_offered`: The session already holds an offer; the first one wins",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "easy_recovery_already_offered": {
                    "summary": "easy_recovery_already_offered: The session already holds an offer; the first one wins",
                    "value": {
                      "statusCode": 409,
                      "code": "easy_recovery_already_offered",
                      "error": "Conflict",
                      "message": "This recovery session already holds an offer. Start again on the new device.",
                      "path": "/v1/wallet/easy-recovery/sessions/q2Z7rT0aV1bX9cD4eF6gHw/offer",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Offer the sealed wallet from the old device",
        "tags": [
          "wallet-easy-recovery"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "easy-recovery-offer",
            "limit": 20,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    },
    "/v1/wallet/easy-recovery/sessions/{id}/claim": {
      "post": {
        "description": "The right code answers the sealed wallet, once: the session reads `claimed` from then on and no longer holds it. A wrong code is a 422 with `details.attemptsLeft`; the fifth wrong code deletes the session and answers 410. Before the old device offered, the answer is 409: poll for `offered` first. A malformed code is a 400 and costs no attempt.\n\nRequires the `payments:write` scope. The shared public key may call it.",
        "operationId": "EasyRecoveryController_claim_v1",
        "parameters": [
          {
            "name": "id",
            "required": true,
            "in": "path",
            "description": "The session id from `POST /v1/wallet/easy-recovery/sessions`, as the QR carries it: 22 base64url characters.",
            "schema": {
              "example": "q2Z7rT0aV1bX9cD4eF6gHw",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ClaimEasyRecoveryDto"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EasyRecoveryClaimedEntity"
                }
              }
            },
            "headers": {
              "ratelimit-limit": {
                "description": "Requests allowed in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 30
                }
              },
              "ratelimit-remaining": {
                "description": "Requests left in the current window.",
                "schema": {
                  "type": "integer",
                  "example": 0
                }
              },
              "ratelimit-reset": {
                "description": "Seconds until the window resets.",
                "schema": {
                  "type": "integer",
                  "example": 42
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/ValidationFailed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "`easy_recovery_not_found`: No such session, or it expired, was claimed or was burned",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "easy_recovery_not_found": {
                    "summary": "easy_recovery_not_found: No such session, or it expired, was claimed or was burned",
                    "value": {
                      "statusCode": 404,
                      "code": "easy_recovery_not_found",
                      "error": "Not Found",
                      "message": "This recovery session does not exist or has expired. Start again on the new device.",
                      "path": "/v1/wallet/easy-recovery/sessions/q2Z7rT0aV1bX9cD4eF6gHw/claim",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "`easy_recovery_not_offered`: Nothing has been offered on the session yet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "easy_recovery_not_offered": {
                    "summary": "easy_recovery_not_offered: Nothing has been offered on the session yet",
                    "value": {
                      "statusCode": 409,
                      "code": "easy_recovery_not_offered",
                      "error": "Conflict",
                      "message": "Nothing has been offered on this session yet. Confirm on the other device first.",
                      "path": "/v1/wallet/easy-recovery/sessions/q2Z7rT0aV1bX9cD4eF6gHw/claim",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "410": {
            "description": "`easy_recovery_burned`: That was the last wrong code allowed: the session was deleted",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "easy_recovery_burned": {
                    "summary": "easy_recovery_burned: That was the last wrong code allowed: the session was deleted",
                    "value": {
                      "statusCode": 410,
                      "code": "easy_recovery_burned",
                      "error": "Gone",
                      "message": "Too many wrong codes: this recovery session was deleted. Start again on the new device.",
                      "path": "/v1/wallet/easy-recovery/sessions/q2Z7rT0aV1bX9cD4eF6gHw/claim",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "`easy_recovery_code_invalid`: Wrong code; `details.attemptsLeft` says how many more the session survives",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ApiErrorBodyEntity"
                },
                "examples": {
                  "easy_recovery_code_invalid": {
                    "summary": "easy_recovery_code_invalid: Wrong code; `details.attemptsLeft` says how many more the session survives",
                    "value": {
                      "statusCode": 422,
                      "code": "easy_recovery_code_invalid",
                      "error": "Unprocessable Entity",
                      "message": "That code is not the one shown on the other device.",
                      "details": {
                        "attemptsLeft": 4
                      },
                      "path": "/v1/wallet/easy-recovery/sessions/q2Z7rT0aV1bX9cD4eF6gHw/claim",
                      "timestamp": "2026-09-01T12:00:00.000Z"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "500": {
            "$ref": "#/components/responses/InternalError"
          }
        },
        "summary": "Claim the sealed wallet with the code on the old device",
        "tags": [
          "wallet-easy-recovery"
        ],
        "x-cosmos-public-key": true,
        "x-cosmos-rate-limit": [
          {
            "name": "easy-recovery-claim",
            "limit": 30,
            "windowMs": 600000
          }
        ],
        "x-cosmos-scopes": [
          "payments:write"
        ]
      }
    }
  },
  "info": {
    "title": "Cosmos Pay Payments API",
    "description": "Payments API for merchants and wallets. It covers: payment intents on Stellar, Solana and Monad (with payment links, customers and a product catalog); swaps (Stellar path payments, Solana via Jupiter, Monad via Kuru Flow), cross-chain swaps across Stellar, Solana, Monad and other networks through NEAR Intents, and USDT0 transfers from Stellar to EVM networks through LayerZero; private payments with a hidden amount on Stellar; Stellar liquidity pools and DeFindex yield vaults; fiat on/offramp and KYC through BlindPay; and webhooks that notify your server of payment events. Liquidity pools, DeFindex, USDT0, private payments and the SEP-10 and SEP-30 routes are Stellar only. Paths already include the version (`/v1/...`). Pick the matching server and security scheme below. **Every failure returns the same envelope** (`ApiErrorBodyEntity`), and `code` is the part to branch on: `message` is prose and may be reworded. Each operation documents only the statuses it can really return: `429` appears where a budget is declared (the budget itself is published as `x-cosmos-rate-limit`), `502`/`503`/`504` where the route calls a provider (`x-cosmos-upstream`), and neither `401` nor `403` on the probes that need no credentials (`x-cosmos-public`). **Every operation says who may call it.** On a route that takes an API key, the description ends with the scope the key must hold, also published as `x-cosmos-scopes` (all of) and `x-cosmos-scopes-any` (one of); a key with the `admin` role passes every scope check, and `x-cosmos-public-key` marks the routes the shared public key may call. A route that takes no API key (`x-cosmos-public`) says in its description how it is called. Authenticate every request with your secret API key in the `Authorization: Bearer <apiKey>` header.",
    "version": "1.0",
    "contact": {
      "name": "Cosmos Pay",
      "url": "https://dev.cosmospay.lat/docs",
      "email": "organization@cosmospay.lat"
    }
  },
  "tags": [
    {
      "name": "payment-intents",
      "description": "Create, fetch, update, cancel and validate payment intents on Stellar (SEP-7), Solana (Solana Pay) and Monad (EIP-681)."
    },
    {
      "name": "Protected payments",
      "description": "Payments held until delivery. Create a protected payment, choose who confirms delivery and what happens at the deadline, then ship, approve, release or dispute it. The buyer pays USDC into a smart contract on Stellar, and the funds are released to your wallet on the terms you chose."
    },
    {
      "name": "Protected payment links",
      "description": "The buyer side of a protected payment, called from the hosted checkout without an API key: read the payment, fund it from a Stellar wallet, confirm delivery, release it or open a dispute."
    },
    {
      "name": "swaps",
      "description": "Quote, create, sign and submit same-chain swaps: Stellar path payments by default, Solana through Jupiter and Monad through Kuru Flow with `chain`."
    },
    {
      "name": "cross-chain-swaps",
      "description": "Swaps between every network NEAR Intents reaches, settled by NEAR Intents: quote, get a deposit address, pay it, and follow the swap to its outcome."
    },
    {
      "name": "usdt0",
      "description": "USDT0 out of Stellar through LayerZero: quote, build the Soroban transaction the holder signs, submit it and follow the message to its destination. Native USDT on Ethereum, USDT0 elsewhere; mainnet only."
    },
    {
      "name": "zk-payments",
      "description": "Payments on Stellar whose amount stays hidden on-chain. Create a private payment, list and read them; the merchant receives the amount minus the private-payment commission (see https://cosmospay.lat/pricing)."
    },
    {
      "name": "zk-checkout",
      "description": "What the payer's browser reads and calls without a key: one private payment, the network's confidential-token setup, and the confirmation of the two confidential transfers that pay it."
    },
    {
      "name": "liquidity-pools",
      "description": "Deposit into and withdraw from Stellar AMM pools, and track your positions."
    },
    {
      "name": "assets",
      "description": "The asset registry: which (code, issuer) pairs exist per network and who issues them. `verified` is a claim about the issuer’s identity, not about quality."
    },
    {
      "name": "payment-links",
      "description": "The payer’s view of one payment link, served without a key to the hosted checkout on payments.cosmospay.lat. The link id is the capability: anyone holding it can read the amount, the address to pay and the live status, and nothing about the merchant."
    },
    {
      "name": "public-key",
      "description": "The shared public API key, served without a key to wallets that have no account yet. Not a secret: what it may call is confined server-side to routes that return no per-consumer data."
    },
    {
      "name": "plugins",
      "description": "Extensions served under a slug: list them, install one for your account, and call its queries and commands."
    },
    {
      "name": "aliases",
      "description": "Payment handles: resolve a name to its addresses, and claim or manage one with a signature by each address it points at."
    },
    {
      "name": "onramp",
      "description": "Fiat in: quotes, payins, virtual accounts, and the trustline for the asset delivered."
    },
    {
      "name": "offramp",
      "description": "Fiat out: quotes, payout authorization, and payout tracking."
    },
    {
      "name": "kyc",
      "description": "Receivers, their review and terms of service, and KYC documents."
    },
    {
      "name": "kyc-accounts",
      "description": "A receiver's blockchain wallets and fiat bank accounts, the bank rails and the fields each rail asks for."
    },
    {
      "name": "DeFindex",
      "description": "Yield vaults on DeFindex: discover vaults, read a balance, and build the unsigned deposit or withdrawal the account signs before it is submitted."
    },
    {
      "name": "wallet-auth",
      "description": "The Cosmos Pay Wallet’s own sign-in: Authentik (OpenID Connect), Google, GitHub or an emailed code. It proves who a person is and never touches a key; the seed backup it stores is sealed on the device under a password this service never sees."
    },
    {
      "name": "recovery",
      "description": "Served by the two recovery deployments only. Standard SEP-10 web authentication and SEP-30 account recovery: each server holds half of what a recovery signature needs, and proves the person’s inbox on its own."
    },
    {
      "name": "wallet-easy-recovery",
      "description": "Move a wallet between two devices through a five-minute mailbox this service cannot open."
    },
    {
      "name": "webhooks",
      "description": "Register endpoints, manage them, and inspect delivery attempts for payment events."
    },
    {
      "name": "products",
      "description": "CRUD for your product catalog."
    },
    {
      "name": "customers",
      "description": "CRUD for customers and their payment stats."
    },
    {
      "name": "analytics",
      "description": "Account summary, balances and operational logs."
    },
    {
      "name": "activity",
      "description": "Report what your own client did (errors, timings, transactions) and read it back. Unlike the API logs, which only ever see requests that reached this service, these are the events that happen entirely on a device: a crash, a cancelled signature, a screen that failed before any request left it."
    },
    {
      "name": "health",
      "description": "Liveness and readiness probes."
    }
  ],
  "servers": [
    {
      "url": "https://api.cosmospay.lat/cosmos-api",
      "description": "Cosmos Pay API"
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API key",
        "description": "Your Cosmos Pay secret API key, sent as `Authorization: Bearer <apiKey>`."
      },
      "sep-token": {
        "scheme": "bearer",
        "bearerFormat": "JWT",
        "type": "http",
        "description": "A token from THIS recovery server: `POST /v1/sep10/auth` (the account's key) or `POST /v1/sep30/identity` / `/identity/email/verify` (an inbox). The sibling server never accepts it."
      }
    },
    "schemas": {
      "MerchantFeeDto": {
        "type": "object",
        "properties": {
          "bps": {
            "type": "number",
            "description": "The percentage part, in basis points (150 = 1.5%), at most 1000 (10%). Taken from `amount`, rounded down.",
            "example": 150,
            "minimum": 0,
            "maximum": 1000
          },
          "fixed": {
            "type": "string",
            "description": "The fixed part, in the operation's asset (a swap's source asset), as a decimal with at most that asset's decimals. Added to the percentage part.",
            "example": "0.25"
          },
          "wallet": {
            "type": "string",
            "description": "Where the fee is paid: an account on the chain the fee travels on (a Stellar G... account for a Stellar swap; a NEAR account for a swap between chains, which NEAR Intents pays as an app fee).",
            "example": "GBDHAQXQQ75WVBUZ2IX3O7ME7JOKJUOUPUXRNDCORUJODWQCTVUEQ62R",
            "maxLength": 128
          },
          "paidBy": {
            "type": "string",
            "enum": [
              "recipient",
              "payer"
            ],
            "default": "recipient",
            "description": "`recipient`: deducted from `amount` (the receiver gets less, a swap routes less). `payer`: added on top (the payer sends `amount` plus the fee)."
          }
        },
        "description": "A merchant fee to charge on this operation: a percentage, a fixed amount or both, paid on-chain to `wallet`. At least one of `bps` and `fixed` must be above zero.",
        "required": [
          "wallet"
        ]
      },
      "CreateTxPaymentIntentDto": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "Payer's Stellar account: the transaction source.",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"
          },
          "destination": {
            "type": "string",
            "description": "Payee's Stellar account.",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO"
          },
          "amount": {
            "type": "string",
            "description": "Amount as a decimal string (max 7 decimals).",
            "example": "120.1234567"
          },
          "assetCode": {
            "type": "string",
            "description": "Asset code. Omit (or \"XLM\"/\"native\") for native lumens.",
            "example": "USDC"
          },
          "assetIssuer": {
            "type": "string",
            "description": "Issuer account for a non-native asset.",
            "example": "GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB"
          },
          "memo": {
            "type": "string",
            "description": "MEMO_ID (numeric uint64) for idempotency + on-chain identification. Auto-generated when omitted.",
            "example": "123456789"
          },
          "msg": {
            "type": "string",
            "description": "SEP-7 `msg`: shown to the user in their wallet (≤ 300 chars).",
            "example": "Order #24"
          },
          "callback": {
            "type": "string",
            "description": "SEP-7 `callback` where the wallet POSTs the signed XDR, e.g. `url:https://...`.",
            "example": "url:https://merchant.example.com/sep7/callback"
          },
          "checkoutTheme": {
            "type": "string",
            "enum": [
              "classic",
              "split",
              "ticket",
              "card"
            ],
            "default": "classic",
            "description": "Design of the hosted checkout page (`https://payments.cosmospay.lat/<id>`) for this intent. Omit for `classic`. Cosmetic: it is not part of the payment, so `PATCH /v1/payment-intents/{id}` can change it later, and a retry with the same memo returns the stored intent with its stored design.",
            "example": "ticket"
          },
          "merchantFee": {
            "description": "Your own fee on this payment, paid in its asset to `wallet` (a Stellar account that can receive the asset, not `source` or `destination`) by a second payment in the same envelope. `paidBy: recipient` takes it from `amount` (the destination receives `amount` less the fee); `payer` adds it on top. The intent settles only on a transaction that pays both.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "Request to create a Stellar SEP-7 `tx` intent: the payer (`source`) is known, so the service builds the unsigned transaction for it to sign.",
        "required": [
          "source",
          "destination",
          "amount"
        ]
      },
      "MerchantFeeEntity": {
        "type": "object",
        "properties": {
          "bps": {
            "type": "number",
            "description": "The percentage part, in basis points.",
            "example": 150
          },
          "fixed": {
            "type": "string",
            "description": "The fixed part, in `asset`.",
            "example": "0.25"
          },
          "amount": {
            "type": "string",
            "description": "The fee charged: the percentage of `amount` plus the fixed part.",
            "example": "1.75"
          },
          "asset": {
            "type": "string",
            "description": "The asset the fee is paid in.",
            "example": "XLM"
          },
          "wallet": {
            "type": "string",
            "description": "Where the fee is paid.",
            "example": "GBDHAQXQQ75WVBUZ2IX3O7ME7JOKJUOUPUXRNDCORUJODWQCTVUEQ62R"
          },
          "paidBy": {
            "type": "string",
            "enum": [
              "recipient",
              "payer"
            ],
            "description": "`recipient`: deducted from the amount. `payer`: added on top of it.",
            "example": "recipient"
          }
        },
        "description": "The merchant fee an operation charged, as its record stores it.",
        "required": [
          "bps",
          "fixed",
          "amount",
          "asset",
          "wallet",
          "paidBy"
        ]
      },
      "TxPaymentIntentEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "Payment intent id."
          },
          "kind": {
            "type": "string",
            "enum": [
              "TX",
              "PAY"
            ],
            "example": "TX",
            "description": "Always `TX` for this response."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "Lifecycle status. `SUCCEEDED`, `FAILED` and `CANCELLED` are final; an `EXPIRED` intent still settles on a payment verified later."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "Chain the payment settles on. TX intents are always Stellar."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "Network tier, on every chain: `public` (mainnet) or `testnet` (Stellar testnet, Solana devnet, Monad testnet), the one the API key is for."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "Payer's Stellar account: the transaction source."
          },
          "destination": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "Payee's Stellar account."
          },
          "amount": {
            "type": "string",
            "example": "120.1234567",
            "description": "Amount to pay, as a decimal string (at most 7 decimals)."
          },
          "asset": {
            "type": "string",
            "example": "native",
            "description": "Asset code, or `native` for XLM."
          },
          "assetIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Issuer account of an issued asset; null for XLM."
          },
          "memo": {
            "type": "string",
            "example": "123456789",
            "description": "Mandatory MEMO_ID."
          },
          "chainReference": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "How the payment is found off Stellar. Solana: the Solana Pay `reference` key. Monad with deposit addresses: the intent’s own deposit address, which the link pays. Null otherwise."
          },
          "networkFee": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Deducted before the merchant is paid, in the asset’s units: the relayer’s fee for forwarding a Monad deposit. Null when nothing is."
          },
          "merchantFee": {
            "nullable": true,
            "description": "Your merchant fee on this payment, paid to its wallet in the same transaction; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "msg": {
            "type": "object",
            "nullable": true,
            "example": "Order #24",
            "description": "SEP-7 `msg` shown to the payer in their wallet."
          },
          "callback": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "SEP-7 `callback` where the wallet POSTs the signed XDR (e.g. `url:https://...`)."
          },
          "xdr": {
            "type": "string",
            "description": "Unsigned transaction envelope (base64 XDR).",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "The SEP-7 `web+stellar:tx` link carrying the unsigned envelope."
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",
            "description": "QR code of `uri` (PNG data URL), derived on read."
          },
          "txHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The transaction reported or verified for this intent, in its chain's own form (hex lowercase); null until there is one."
          },
          "reference": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Your own reference for the intent, set with `PATCH`; null until set."
          },
          "checkoutTheme": {
            "type": "string",
            "enum": [
              "classic",
              "split",
              "ticket",
              "card"
            ],
            "example": "classic",
            "description": "Design of the hosted checkout page. `classic` when none was chosen."
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "description": "When the intent expires if unpaid.",
            "example": "2026-06-21T13:34:56.000Z"
          },
          "checkoutSeenAt": {
            "type": "object",
            "nullable": true,
            "description": "When the hosted checkout page last read the intent: null at creation.",
            "example": null
          },
          "checkoutWalletAt": {
            "type": "object",
            "nullable": true,
            "description": "When the payer last opened a wallet from the hosted checkout (its wallet link, the web wallet, the extension or Freighter), as the page reports it. Informational: the status changes only on the chain.",
            "example": null
          },
          "checkoutWalletClosedAt": {
            "type": "object",
            "nullable": true,
            "description": "When the wallet last came back without paying (it declined, or the page was shown again first), as the page reports it; cleared when a wallet opens again.",
            "example": null
          },
          "checkoutSentAt": {
            "type": "object",
            "nullable": true,
            "description": "When the hosted checkout saw the wallet send the payment, as the page reports it: a payment on its way, before the chain confirms it.",
            "example": null
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the intent was created (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the intent itself last changed (ISO 8601)."
          }
        },
        "description": "A Stellar SEP-7 `tx` intent as created: the unsigned envelope for the known payer, its `web+stellar:tx` link and QR.",
        "required": [
          "id",
          "kind",
          "status",
          "chain",
          "network",
          "source",
          "destination",
          "amount",
          "asset",
          "assetIssuer",
          "memo",
          "chainReference",
          "networkFee",
          "merchantFee",
          "msg",
          "callback",
          "xdr",
          "uri",
          "qr",
          "txHash",
          "reference",
          "checkoutTheme",
          "expiresAt",
          "checkoutSeenAt",
          "checkoutWalletAt",
          "checkoutWalletClosedAt",
          "checkoutSentAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "CreatePayPaymentIntentDto": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "Chain the payment settles on. Omit for Stellar. The network (mainnet or test network) is the one your API key is for, as on Stellar."
          },
          "destination": {
            "type": "string",
            "description": "Payee's account on the chain: Stellar G…, Solana base58, Monad 0x….",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO"
          },
          "amount": {
            "type": "string",
            "description": "Amount the destination should receive, in the asset’s own units (XLM, SOL, MON, or the token). Omit to let the user enter it (e.g. donations), but not on Monad, where the amount is part of how the payment is recognised. At most 7 decimals on Stellar; elsewhere, at most the asset’s own decimals.",
            "example": "120.1234567"
          },
          "assetCode": {
            "type": "string",
            "description": "Asset code the destination receives. Omit for the chain’s coin (XLM, SOL, MON). For a Solana or Monad token, the ticker it is labelled with, alongside `assetIssuer`.",
            "example": "USDC"
          },
          "assetIssuer": {
            "type": "string",
            "description": "Stellar: the issuer account. Solana: the SPL mint. Monad: the ERC-20 contract. Omit for the chain’s coin.",
            "example": "GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB"
          },
          "memo": {
            "type": "string",
            "description": "MEMO_ID (numeric uint64): the idempotency key on every chain, and on Stellar the on-chain identification too (on Solana it is recorded with the SPL Memo program). Auto-generated when omitted.",
            "example": "123456789"
          },
          "msg": {
            "type": "string",
            "description": "Shown to the user in their wallet (≤ 300 chars): SEP-7 `msg` on Stellar, the Solana Pay `message`. Not supported on Monad.",
            "example": "pay me with lumens"
          },
          "callback": {
            "type": "string",
            "description": "SEP-7 `callback`, e.g. `url:https://...`. Stellar only.",
            "example": "url:https://merchant.example.com/sep7/callback"
          },
          "checkoutTheme": {
            "type": "string",
            "enum": [
              "classic",
              "split",
              "ticket",
              "card"
            ],
            "default": "classic",
            "description": "Design of the hosted checkout page (`https://payments.cosmospay.lat/<id>`) for this intent. Omit for `classic`. Cosmetic: it is not part of the payment, so `PATCH /v1/payment-intents/{id}` can change it later, and a retry with the same memo returns the stored intent with its stored design.",
            "example": "ticket"
          },
          "merchantFee": {
            "description": "Only with an `amount`: your own fee on this payment, paid in its asset to `wallet` (an account on the link's chain, not `destination`). `paidBy: recipient` takes the fee from `amount`; `payer` adds it on top. Stellar: a SEP-7 `pay` link pays one account, so `uri` is the hosted checkout, which asks for the payer and has `POST /v1/payment-links/{id}/transaction` build the envelope with both payments. Solana: `uri` is a Solana Pay transaction request (`/v1/payment-links/{id}/solana-pay`); a SOL fee goes to an existing account. Monad: needs deposit addresses (`merchant_fee_unsupported` without them); the deposit address pays the fee (PaymentSplitForwarder) and the link asks for the amount, plus the fee when the payer pays it.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "Request to create a `pay` intent: a payment link any wallet can pay on Stellar (SEP-7), Solana (Solana Pay) or Monad (EIP-681).",
        "required": [
          "destination"
        ]
      },
      "PayPaymentIntentEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "Payment intent id."
          },
          "kind": {
            "type": "string",
            "enum": [
              "TX",
              "PAY"
            ],
            "example": "PAY",
            "description": "Always `PAY` for this response."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "Lifecycle status. `SUCCEEDED`, `FAILED` and `CANCELLED` are final; an `EXPIRED` intent still settles on a payment verified later."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "Chain the payment settles on. TX intents are always Stellar."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "Network tier, on every chain: `public` (mainnet) or `testnet` (Stellar testnet, Solana devnet, Monad testnet), the one the API key is for."
          },
          "source": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Always null for PAY."
          },
          "destination": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "Payee account on the intent's chain (Stellar G..., Solana base58, Monad 0x...)."
          },
          "amount": {
            "type": "object",
            "nullable": true,
            "example": "120.1234567",
            "description": "Amount to pay, as a decimal string in the asset's units. Null when the payer chooses it."
          },
          "asset": {
            "type": "string",
            "example": "native",
            "description": "Asset code, or `native` for the chain's coin (XLM, SOL, MON)."
          },
          "assetIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Stellar: the issuer. Solana: the SPL mint. Monad: the ERC-20 contract. Null for the native coin."
          },
          "memo": {
            "type": "string",
            "example": "123456789",
            "description": "Mandatory MEMO_ID."
          },
          "chainReference": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "How the payment is found off Stellar. Solana: the Solana Pay `reference` key. Monad with deposit addresses: the intent’s own deposit address, which the link pays. Null otherwise."
          },
          "networkFee": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Deducted before the merchant is paid, in the asset’s units: the relayer’s fee for forwarding a Monad deposit. Null when nothing is."
          },
          "merchantFee": {
            "nullable": true,
            "description": "Your merchant fee on this payment, paid to its wallet in the same transaction; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "msg": {
            "type": "object",
            "nullable": true,
            "example": "pay me with lumens",
            "description": "Message shown to the payer in their wallet: SEP-7 `msg` on Stellar, the Solana Pay `message` on Solana."
          },
          "callback": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "SEP-7 `callback` (e.g. `url:https://...`). Stellar only."
          },
          "xdr": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Always null for PAY."
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=120.1234567",
            "description": "The payment link: SEP-7 `web+stellar:pay` on Stellar, Solana Pay on Solana, EIP-681 on Monad. With a merchant fee it is the hosted checkout on Stellar and a Solana Pay transaction request on Solana."
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",
            "description": "QR code of `uri` (PNG data URL), derived on read."
          },
          "txHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The transaction reported or verified for this intent, in its chain's own form (hex lowercase); null until there is one."
          },
          "reference": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Your own reference for the intent, set with `PATCH`; null until set."
          },
          "checkoutTheme": {
            "type": "string",
            "enum": [
              "classic",
              "split",
              "ticket",
              "card"
            ],
            "example": "classic",
            "description": "Design of the hosted checkout page. `classic` when none was chosen."
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "description": "When the intent expires if unpaid.",
            "example": "2026-06-21T13:34:56.000Z"
          },
          "checkoutSeenAt": {
            "type": "object",
            "nullable": true,
            "description": "When the hosted checkout page last read the intent: null at creation.",
            "example": null
          },
          "checkoutWalletAt": {
            "type": "object",
            "nullable": true,
            "description": "When the payer last opened a wallet from the hosted checkout (its wallet link, the web wallet, the extension or Freighter), as the page reports it. Informational: the status changes only on the chain.",
            "example": null
          },
          "checkoutWalletClosedAt": {
            "type": "object",
            "nullable": true,
            "description": "When the wallet last came back without paying (it declined, or the page was shown again first), as the page reports it; cleared when a wallet opens again.",
            "example": null
          },
          "checkoutSentAt": {
            "type": "object",
            "nullable": true,
            "description": "When the hosted checkout saw the wallet send the payment, as the page reports it: a payment on its way, before the chain confirms it.",
            "example": null
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the intent was created (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the intent itself last changed (ISO 8601)."
          }
        },
        "description": "A `pay` intent as created: a payment link any wallet can pay (SEP-7 `pay` on Stellar, Solana Pay on Solana, EIP-681 on Monad) and its QR.",
        "required": [
          "id",
          "kind",
          "status",
          "chain",
          "network",
          "source",
          "destination",
          "amount",
          "asset",
          "assetIssuer",
          "memo",
          "chainReference",
          "networkFee",
          "merchantFee",
          "msg",
          "callback",
          "xdr",
          "uri",
          "qr",
          "txHash",
          "reference",
          "checkoutTheme",
          "expiresAt",
          "checkoutSeenAt",
          "checkoutWalletAt",
          "checkoutWalletClosedAt",
          "checkoutSentAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "PaymentIntentEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "Payment intent id."
          },
          "kind": {
            "type": "string",
            "enum": [
              "TX",
              "PAY"
            ],
            "example": "TX",
            "description": "`TX`: an unsigned Stellar transaction built for a known payer. `PAY`: a payment link any wallet can pay."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "Lifecycle status. `SUCCEEDED`, `FAILED` and `CANCELLED` are final; an `EXPIRED` intent still settles on a payment verified later."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "Chain the payment settles on. TX intents are always Stellar."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "Network tier, on every chain: `public` (mainnet) or `testnet` (Stellar testnet, Solana devnet, Monad testnet), the one the API key is for."
          },
          "source": {
            "type": "object",
            "nullable": true,
            "example": "Greally…56charpublickey",
            "description": "Payer account (null for PAY intents)."
          },
          "destination": {
            "type": "string",
            "example": "GASMERCHANT…56charpublickey",
            "description": "Payee account on the intent's chain (Stellar G..., Solana base58, Monad 0x...)."
          },
          "amount": {
            "type": "object",
            "nullable": true,
            "example": "25.5",
            "description": "Amount to pay, as a decimal string in the asset's units. Null for a `PAY` intent with an open amount."
          },
          "asset": {
            "type": "string",
            "example": "native",
            "description": "Asset code, or \"native\" for the chain’s coin (XLM, SOL, MON)."
          },
          "assetIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Stellar: the issuer. Solana: the SPL mint. Monad: the ERC-20 contract."
          },
          "memo": {
            "type": "string",
            "example": "123456789",
            "description": "Mandatory MEMO_ID (auto-generated if not provided)."
          },
          "chainReference": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "How the payment is found off Stellar. Solana: the Solana Pay `reference` key. Monad with deposit addresses: the intent’s own deposit address, which the link pays. Null otherwise."
          },
          "networkFee": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Deducted before the merchant is paid, in the asset’s units: the relayer’s fee for forwarding a Monad deposit. Null when nothing is."
          },
          "merchantFee": {
            "nullable": true,
            "description": "Your merchant fee on this payment, paid to its wallet in the same transaction; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "msg": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "SEP-7 msg."
          },
          "callback": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "SEP-7 callback."
          },
          "xdr": {
            "type": "object",
            "nullable": true,
            "description": "Unsigned transaction envelope (null for PAY intents).",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "description": "The payment link: SEP-7 on Stellar (`tx` for TX intents, `pay` for PAY), a Solana Pay transfer request on Solana, EIP-681 on Monad.",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…"
          },
          "qr": {
            "type": "string",
            "description": "QR code of `uri` (PNG data URL), derived on read.",
            "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…"
          },
          "txHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The transaction reported or verified for this intent, in its chain's own form (hex lowercase); null until there is one."
          },
          "reference": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Your own reference for the intent, set with `PATCH`; null until set."
          },
          "checkoutTheme": {
            "type": "string",
            "enum": [
              "classic",
              "split",
              "ticket",
              "card"
            ],
            "example": "classic",
            "description": "Design of the hosted checkout page. `classic` when none was chosen."
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "description": "When an unpaid intent expires. A payment verified later still settles it.",
            "example": "2026-06-21T13:34:56.000Z"
          },
          "checkoutSeenAt": {
            "type": "object",
            "nullable": true,
            "description": "When the hosted checkout page (payments.cosmospay.lat/{id}) last read the intent while it was open: the page polls while a payer has it open, so a value from the last 30 seconds means someone is on the payment page now. Updated at most every 10 seconds; null until a page opened it.",
            "example": "2026-06-21T12:35:10.000Z"
          },
          "checkoutWalletAt": {
            "type": "object",
            "nullable": true,
            "description": "When the payer last opened a wallet from the hosted checkout (its wallet link, the web wallet, the extension or Freighter), as the page reports it. Informational: the status changes only on the chain.",
            "example": null
          },
          "checkoutWalletClosedAt": {
            "type": "object",
            "nullable": true,
            "description": "When the wallet last came back without paying (it declined, or the page was shown again first), as the page reports it; cleared when a wallet opens again.",
            "example": null
          },
          "checkoutSentAt": {
            "type": "object",
            "nullable": true,
            "description": "When the hosted checkout saw the wallet send the payment, as the page reports it: a payment on its way, before the chain confirms it.",
            "example": null
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the intent was created (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the intent itself last changed (ISO 8601)."
          }
        },
        "description": "A payment intent: one expected payment to a merchant on Stellar, Solana or Monad, with its payment link and lifecycle status.",
        "required": [
          "id",
          "kind",
          "status",
          "chain",
          "network",
          "source",
          "destination",
          "amount",
          "asset",
          "assetIssuer",
          "memo",
          "chainReference",
          "networkFee",
          "merchantFee",
          "msg",
          "callback",
          "xdr",
          "uri",
          "qr",
          "txHash",
          "reference",
          "checkoutTheme",
          "expiresAt",
          "checkoutSeenAt",
          "checkoutWalletAt",
          "checkoutWalletClosedAt",
          "checkoutSentAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "PaymentIntentListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The payment intents on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PaymentIntentEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "Number of intents matching the filters, across every page."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "Page size applied (1 to 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Number of intents skipped before this page."
          }
        },
        "description": "One page of the consumer's payment intents on the key's network, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "PaymentIntentTransitionEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clxtransition0001",
            "description": "Transition id."
          },
          "intentId": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "Id of the payment intent that changed."
          },
          "fromStatus": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "Status before the change."
          },
          "toStatus": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "example": "SUBMITTED",
            "description": "Status after the change."
          },
          "txHash": {
            "type": "object",
            "nullable": true,
            "example": "3389e9f0…",
            "description": "The transaction the change carried, if any."
          },
          "actor": {
            "type": "string",
            "example": "api",
            "description": "api | validate | observer | system"
          },
          "reason": {
            "type": "object",
            "nullable": true,
            "description": "Why the status changed (e.g. `on-chain payment confirmed`), when recorded."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the change happened (ISO 8601)."
          }
        },
        "description": "One status change in a payment intent's audit trail.",
        "required": [
          "id",
          "intentId",
          "fromStatus",
          "toStatus",
          "actor",
          "createdAt"
        ]
      },
      "ValidatePaymentIntentDto": {
        "type": "object",
        "properties": {
          "txHash": {
            "type": "string",
            "description": "The transaction to validate against this intent, in its chain’s own form: a Stellar hash (64 hex), a Solana signature (base58) or a Monad hash (0x + 64 hex). It must be the one the intent’s chain uses.",
            "example": "3389e9f0d6b3e3f1c2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9"
          }
        },
        "description": "The transaction to check against a payment intent, which settles the intent when it pays it.",
        "required": [
          "txHash"
        ]
      },
      "ValidationOutcomeEntity": {
        "type": "object",
        "properties": {
          "valid": {
            "type": "boolean",
            "example": true,
            "description": "True when the intent is `SUCCEEDED`: this transaction paid it, or it was already paid."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "example": "SUCCEEDED",
            "description": "The intent status after the check."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Why validation failed, when `valid` is false."
          },
          "paymentIntent": {
            "description": "The intent after the check; omitted when the check changed nothing.",
            "allOf": [
              {
                "$ref": "#/components/schemas/PaymentIntentEntity"
              }
            ]
          }
        },
        "description": "Result of checking a transaction against a payment intent.",
        "required": [
          "valid",
          "status"
        ]
      },
      "UpdatePaymentIntentDto": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "description": "The new status, following the transition graph. `SUCCEEDED` needs a `txHash` and is checked on-chain like `validate`."
          },
          "txHash": {
            "type": "string",
            "description": "The transaction once it is submitted, in its chain’s own form: a Stellar hash (64 hex), a Solana signature (base58) or a Monad hash (0x + 64 hex). Hex is stored lowercase. A transaction already recorded on another of your payment intents is refused with 409 `idempotency_conflict`.",
            "example": "3389e9f0d6b3e3f1c2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9",
            "pattern": "^(?:[0-9a-fA-F]{64}|0x[0-9a-fA-F]{64}|[1-9A-HJ-NP-Za-km-z]{80,90})$"
          },
          "reference": {
            "type": "string",
            "description": "Merchant reference.",
            "example": "order_1234"
          },
          "checkoutTheme": {
            "type": "string",
            "enum": [
              "classic",
              "split",
              "ticket",
              "card"
            ],
            "description": "Design of the hosted checkout page (`https://payments.cosmospay.lat/<id>`). Accepted in any status, final ones included, alone or with the other fields: it changes nothing about the payment.",
            "example": "split"
          }
        },
        "description": "Changes to a payment intent: send only the fields that change."
      },
      "DeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "Id of the deleted payment intent."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirmation that a payment intent was deleted.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "PublicPaymentLinkEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cmh4x2k9a0001l70g8v5q3z2w",
            "description": "The payment intent id. It is also the capability: anyone holding it can read this."
          },
          "kind": {
            "type": "string",
            "enum": [
              "TX",
              "PAY"
            ],
            "example": "PAY",
            "description": "`PAY`: a link the wallet builds the payment from. `TX`: a Stellar envelope built for one known payer, carried inside `uri`."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "Chain the payment settles on."
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "example": "public",
            "description": "Network tier: `public` (mainnet) or `testnet` (Stellar testnet, Solana devnet, Monad testnet)."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "CANCELLED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "The stored status. An unpaid intent past `expiresAt` reads `PENDING` until the observer expires it, and `EXPIRED` is not final: a payment verified on-chain later still moves it to `SUCCEEDED`."
          },
          "payTo": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "The address the payer sends to, always the one inside `uri`. Stellar and Solana: the merchant’s account. Monad with a relayer: the intent’s own deposit address, which forwards the payment to the merchant less `networkFee`."
          },
          "amount": {
            "type": "string",
            "nullable": true,
            "example": "25.5",
            "description": "Decimal, in the asset’s units. Null: the payer chooses."
          },
          "asset": {
            "type": "string",
            "example": "native",
            "description": "Asset code, or `native` for the chain’s coin (XLM, SOL, MON)."
          },
          "assetIssuer": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Stellar: the issuer. Solana: the SPL mint. Monad: the ERC-20 contract. Null for the native coin."
          },
          "memo": {
            "type": "string",
            "example": "4127759120438726917",
            "description": "The intent’s MEMO_ID. On Stellar the payment must carry it, and the link does."
          },
          "msg": {
            "type": "string",
            "nullable": true,
            "example": "Order #24",
            "description": "The message the merchant attached for the payer."
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:pay?destination=GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO&amount=25.5&memo=4127759120438726917&memo_type=MEMO_ID&msg=Order+%2324",
            "description": "The payment link, exactly as the wallet opens it: SEP-7 on Stellar, Solana Pay on Solana, EIP-681 on Monad. It is the same link the merchant handed out, so it carries what the wallet needs: a SEP-7 `callback` the merchant set and, for a `TX` intent, the unsigned envelope."
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",
            "description": "QR code of `uri` (PNG data URL), derived on read."
          },
          "txHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The transaction reported or verified for this intent."
          },
          "networkFee": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Deducted before the merchant is paid, in the asset’s units: the relayer’s fee for forwarding a Monad deposit. Null when nothing is."
          },
          "merchantFee": {
            "nullable": true,
            "description": "A fee the merchant charges on this payment, paid to its own wallet in the same transaction; show it to the payer. With `paidBy: payer` the payer sends `amount` plus it. Null when there is none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "payerAccountRequired": {
            "type": "boolean",
            "example": false,
            "description": "True when the payment cannot be one link (a Stellar link with a merchant fee: SEP-7 `pay` pays one account). Ask the payer for their account, then `POST /v1/payment-links/{id}/transaction` builds the envelope to sign; `uri` is the hosted checkout then, not a wallet link."
          },
          "expiresAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time",
            "example": "2026-10-24T13:34:56.000Z",
            "description": "When an unpaid intent expires. A payment verified later still settles it."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "example": "2026-10-24T12:34:56.000Z",
            "description": "When the intent was created (ISO 8601)."
          },
          "checkoutTheme": {
            "type": "string",
            "enum": [
              "classic",
              "split",
              "ticket",
              "card"
            ],
            "example": "classic",
            "description": "The design the merchant chose for this checkout page; render it. `classic` when none was chosen."
          }
        },
        "description": "A payment intent as its payer may see it, read by id with no API key: only what a checkout page needs, never the merchant's private fields.",
        "required": [
          "id",
          "kind",
          "chain",
          "network",
          "status",
          "payTo",
          "amount",
          "asset",
          "assetIssuer",
          "memo",
          "msg",
          "uri",
          "qr",
          "txHash",
          "networkFee",
          "merchantFee",
          "payerAccountRequired",
          "expiresAt",
          "createdAt",
          "checkoutTheme"
        ]
      },
      "PayerTransactionDto": {
        "type": "object",
        "properties": {
          "account": {
            "type": "string",
            "description": "The Stellar account that will pay and sign: the envelope is built on its sequence number, so it must exist on the link’s network.",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"
          }
        },
        "description": "The payer of a Stellar payment link with a merchant fee, for whom the service builds the envelope to sign.",
        "required": [
          "account"
        ]
      },
      "PayerTransactionEntity": {
        "type": "object",
        "properties": {
          "xdr": {
            "type": "string",
            "description": "The unsigned transaction envelope (base64 XDR): two payments, to the merchant and to the fee wallet, with the link’s MEMO_ID.",
            "example": "AAAAAgAAAAA..."
          },
          "uri": {
            "type": "string",
            "description": "The SEP-7 `web+stellar:tx` link a wallet opens to sign it.",
            "example": "web+stellar:tx?xdr=AAAAAgAAAAA..."
          },
          "qr": {
            "type": "string",
            "description": "The QR of `uri`, as a PNG data URL.",
            "example": "data:image/png;base64,iVBORw0KGgo..."
          }
        },
        "description": "The unsigned Stellar envelope a payment link with a merchant fee asks its payer to sign, with its SEP-7 link and QR.",
        "required": [
          "xdr",
          "uri",
          "qr"
        ]
      },
      "CheckoutEventDto": {
        "type": "object",
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "walletOpened",
              "walletClosed",
              "sent"
            ],
            "description": "`walletOpened`: the payer opened a wallet from the page (the wallet link, the web wallet, the extension, Freighter). `walletClosed`: the wallet came back without paying (it declined, or the page was shown again first). `sent`: the page saw the wallet send the payment.",
            "example": "walletOpened"
          }
        },
        "description": "What the payer did with a wallet, as the hosted checkout page reports it. Informational: the intent status changes only on the chain.",
        "required": [
          "event"
        ]
      },
      "SolanaPayInfoEntity": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "example": "Cosmos Pay",
            "description": "Who requests the payment."
          },
          "icon": {
            "type": "string",
            "example": "https://payments.cosmospay.lat/android-chrome-512x512.png",
            "description": "An absolute https URL of an image the wallet shows."
          }
        },
        "description": "Answer to a Solana Pay transaction request GET: the label and icon the wallet shows before asking for the account.",
        "required": [
          "label",
          "icon"
        ]
      },
      "SolanaPayAccountDto": {
        "type": "object",
        "properties": {
          "account": {
            "type": "string",
            "description": "The payer’s account (base58), which pays the fee and signs.",
            "example": "7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU"
          }
        },
        "description": "What a wallet POSTs to a Solana Pay transaction request: the account that will sign and pay.",
        "required": [
          "account"
        ]
      },
      "SolanaPayTransactionEntity": {
        "type": "object",
        "properties": {
          "transaction": {
            "type": "string",
            "description": "The unsigned transaction (base64 wire bytes): the payment to the merchant, carrying the link’s reference, the merchant fee to its wallet, and the link’s memo. Fee payer: the account that asked.",
            "example": "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA..."
          },
          "message": {
            "type": "string",
            "description": "The link’s message, for the wallet to show.",
            "example": "Order #24"
          }
        },
        "description": "Answer to a Solana Pay transaction request POST: the unsigned transaction the wallet signs.",
        "required": [
          "transaction"
        ]
      },
      "CustomerWalletDto": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "solana",
            "description": "The chain the wallet is on."
          },
          "address": {
            "type": "string",
            "example": "7EcDhSYGxXyscszYEp35KHN8vvw3svAuLKTzXwCFLtV",
            "description": "The address on that chain: a Stellar account (G..., checksum verified), a Solana address (base58, 32 bytes) or a Monad address (0x + 40 hex, any case; stored EIP-55 checksummed). Payment intents whose payer (`source`) is this address count toward the customer."
          },
          "label": {
            "type": "string",
            "example": "Phantom",
            "description": "A name for the wallet, shown beside the address."
          }
        },
        "description": "One wallet of a customer: the chain it is on and its address there.",
        "required": [
          "chain",
          "address"
        ]
      },
      "CreateCustomerDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Acme Inc.",
            "description": "Customer name (1 to 120 characters)."
          },
          "alias": {
            "type": "string",
            "example": "Acme (billing)",
            "description": "An alternative display name (at most 120 characters)."
          },
          "note": {
            "type": "string",
            "example": "VIP customer, net-30 terms.",
            "description": "Free-text note about the customer (at most 500 characters)."
          },
          "email": {
            "type": "string",
            "example": "billing@acme.com",
            "description": "Contact email address (at most 160 characters)."
          },
          "account": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "deprecated": true,
            "description": "Deprecated: use `wallets`. One wallet, its chain read from its shape: a Stellar account (G..., checksum verified), a Solana address (base58, 32 bytes) or a Monad address (0x + 40 hex, any case; stored EIP-55 checksummed). It is added to `wallets`."
          },
          "wallets": {
            "description": "The customer's wallets, on any chain payments settle on, up to 20. Payment intents paid from any of them count toward the customer. A wallet belongs to one customer: one that another customer of yours already holds answers `409 customer_wallet_taken`.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerWalletDto"
            }
          },
          "reference": {
            "type": "string",
            "example": "cust_001",
            "description": "Your own reference for the customer (at most 120 characters)."
          }
        },
        "description": "A customer to create: a merchant-managed record whose wallets' payments count toward it.",
        "required": [
          "name"
        ]
      },
      "CustomerWalletEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cw4f0c2a9d1b7e83c5a6f9d2e1b0c3a7f8",
            "description": "Wallet id, used to remove it from the customer."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "The chain the wallet is on."
          },
          "address": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "The address, in its chain's stored spelling (EIP-55 on Monad)."
          },
          "label": {
            "type": "object",
            "nullable": true,
            "example": "Treasury",
            "description": "A name for the wallet, shown beside the address; null when none was given."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the wallet was added (ISO 8601)."
          }
        },
        "description": "A wallet of a customer, on one chain.",
        "required": [
          "id",
          "chain",
          "address",
          "createdAt"
        ]
      },
      "CustomerEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xcust00001",
            "description": "Customer id."
          },
          "name": {
            "type": "string",
            "example": "Ada Lovelace",
            "description": "Customer name."
          },
          "alias": {
            "type": "object",
            "nullable": true,
            "example": "Acme (billing)",
            "description": "Alternative display name; null when none was given."
          },
          "email": {
            "type": "object",
            "nullable": true,
            "example": "ada@example.com",
            "description": "Contact email address; null when none was given."
          },
          "wallets": {
            "description": "The customer's wallets, oldest first, on any chain payments settle on.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerWalletEntity"
            }
          },
          "account": {
            "type": "object",
            "nullable": true,
            "deprecated": true,
            "description": "Deprecated: read `wallets`. The first wallet's address, kept for clients written when a customer held one account; null without wallets.",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO"
          },
          "note": {
            "type": "object",
            "nullable": true,
            "example": "Prefers wire settlement",
            "description": "Free-text note about the customer; null when none was given."
          },
          "reference": {
            "type": "object",
            "nullable": true,
            "example": "ext_4821",
            "description": "Your own reference for the customer; `auto` for a payer added automatically from a settled payment; null when none."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the customer was created (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:57.000Z",
            "description": "When the customer last changed (ISO 8601)."
          }
        },
        "description": "A merchant-managed customer record with its wallets.",
        "required": [
          "id",
          "name",
          "wallets",
          "createdAt",
          "updatedAt"
        ]
      },
      "CustomerWithStatsEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xcust00001",
            "description": "Customer id."
          },
          "name": {
            "type": "string",
            "example": "Ada Lovelace",
            "description": "Customer name."
          },
          "alias": {
            "type": "object",
            "nullable": true,
            "example": "Acme (billing)",
            "description": "Alternative display name; null when none was given."
          },
          "email": {
            "type": "object",
            "nullable": true,
            "example": "ada@example.com",
            "description": "Contact email address; null when none was given."
          },
          "wallets": {
            "description": "The customer's wallets, oldest first, on any chain payments settle on.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerWalletEntity"
            }
          },
          "account": {
            "type": "object",
            "nullable": true,
            "deprecated": true,
            "description": "Deprecated: read `wallets`. The first wallet's address, kept for clients written when a customer held one account; null without wallets.",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO"
          },
          "note": {
            "type": "object",
            "nullable": true,
            "example": "Prefers wire settlement",
            "description": "Free-text note about the customer; null when none was given."
          },
          "reference": {
            "type": "object",
            "nullable": true,
            "example": "ext_4821",
            "description": "Your own reference for the customer; `auto` for a payer added automatically from a settled payment; null when none."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the customer was created (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:57.000Z",
            "description": "When the customer last changed (ISO 8601)."
          },
          "payments": {
            "type": "number",
            "description": "Payment intents whose payer (`source`) is one of this customer’s wallets, on that wallet's chain and the network the API key targets.",
            "example": 12
          },
          "succeeded": {
            "type": "number",
            "description": "How many of those succeeded.",
            "example": 11
          },
          "total": {
            "type": "string",
            "description": "Gross settled volume, an exact decimal string.",
            "example": "1042.5"
          }
        },
        "description": "A customer with the payment counters of the intents paid from its wallets, on the key's network.",
        "required": [
          "id",
          "name",
          "wallets",
          "createdAt",
          "updatedAt",
          "payments",
          "succeeded",
          "total"
        ]
      },
      "CustomerListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The customers on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomerWithStatsEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Total matching rows, not the page length.",
            "example": 137
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "Page size applied (1 to 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Number of customers skipped before this page."
          }
        },
        "description": "One page of the consumer's customers, newest first, each with its payment counters.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "UpdateCustomerDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Acme Inc.",
            "description": "Customer name (1 to 120 characters)."
          },
          "alias": {
            "type": "string",
            "example": "Acme (billing)",
            "description": "An alternative display name (at most 120 characters)."
          },
          "note": {
            "type": "string",
            "example": "VIP customer, net-30 terms.",
            "description": "Free-text note about the customer (at most 500 characters)."
          },
          "email": {
            "type": "string",
            "example": "billing@acme.com",
            "description": "Contact email address (at most 160 characters)."
          },
          "reference": {
            "type": "string",
            "example": "cust_001",
            "description": "Your own reference for the customer (at most 120 characters)."
          },
          "account": {
            "type": "object",
            "nullable": true,
            "deprecated": true,
            "description": "Deprecated: manage wallets with `POST` and `DELETE /v1/customers/{id}/wallets`. The customer's first wallet: an address replaces it (or adds one), its chain read from its shape; null removes it."
          }
        },
        "description": "Changes to a customer's own fields; only the fields sent change. Wallets change through `/v1/customers/{id}/wallets`."
      },
      "CustomerDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xcust00001",
            "description": "Id of the deleted customer."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirmation that a customer and its wallets were deleted.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "CustomerWalletDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cw4f0c2a9d1b7e83c5a6f9d2e1b0c3a7f8",
            "description": "Id of the removed wallet."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirmation that a wallet was removed from a customer.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "SwapPathHop": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "yXLM",
            "description": "The intermediate asset. Stellar: its code, or `native` for XLM. Solana: the SPL mint address of a token on Jupiter's route (SOL appears as the wrapped SOL mint, never `native`). Monad routes report no hops."
          },
          "issuer": {
            "type": "object",
            "nullable": true,
            "example": "GARDNV3Q7YGT4AKSDF25LT32YSCCW4EV22Y2TV3I2PU2MMXJTEDL5T55",
            "description": "Issuer of a non-native Stellar hop; null for native XLM, and always null on Solana."
          }
        },
        "description": "One intermediate asset on a swap's route: a Stellar asset (code and issuer), or an SPL mint on Solana with a null issuer.",
        "required": [
          "code",
          "issuer"
        ]
      },
      "ChainSwapCreatedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm1x2y3z4a5b6c7d8e9f0g1h2",
            "description": "The swap's id."
          },
          "chain": {
            "type": "string",
            "enum": [
              "solana",
              "monad"
            ],
            "example": "solana",
            "description": "The chain the swap runs on."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always mainnet."
          },
          "provider": {
            "type": "string",
            "enum": [
              "jupiter",
              "kuru"
            ],
            "example": "jupiter",
            "description": "The aggregator that priced and built the swap: `jupiter` on Solana, `kuru` (Kuru Flow) on Monad."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "The swap's status: PENDING (built, not yet submitted), SUBMITTED (broadcast, awaiting the chain), SUCCEEDED, FAILED or EXPIRED."
          },
          "source": {
            "type": "string",
            "example": "13QkxhNMrTPxoCkRdYdJ65tFuwXPhL5gLS2Z5Nr6gjRK",
            "description": "The wallet that signs, pays and receives."
          },
          "sendAsset": {
            "type": "string",
            "example": "native",
            "description": "`native` (SOL / MON), or the SPL mint / ERC-20 address."
          },
          "sendAmount": {
            "type": "string",
            "example": "0.1",
            "description": "Gross amount of the sold asset, as a decimal string in its own units."
          },
          "destAsset": {
            "type": "string",
            "example": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
            "description": "The asset bought: `native` (SOL / MON), or the SPL mint / ERC-20 address."
          },
          "destEstimated": {
            "type": "string",
            "example": "11.87",
            "description": "Quoted output, net of the commission."
          },
          "destMin": {
            "type": "string",
            "example": "11.81",
            "description": "On-chain minimum after slippage."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points (50 = 0.5%), taken from the output."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.059",
            "description": "The commission, in the destination asset (taken from the output)."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "Slippage tolerance used to derive `destMin`, in basis points."
          },
          "path": {
            "description": "Intermediate assets of the route: SPL mints on Solana (with a null issuer); always empty on Monad.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SwapPathHop"
            }
          },
          "transaction": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "encoding": "base64",
              "data": "AQAAAAAAAAAAAAAAA…"
            },
            "description": "What the wallet signs. Solana: `{ encoding: \"base64\", data, lastValidBlockHeight }`, an unsigned VersionedTransaction. Monad: `{ to, data, value, chainId }`, a call the wallet signs as an EIP-1559 transaction (it fills nonce and gas)."
          },
          "approval": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "example": null,
            "description": "Monad only, selling an ERC-20 whose allowance is short: the exact `approve` call `{ to, data, value, chainId }` to send and confirm first. The wallet broadcasts it itself."
          },
          "txHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The Solana signature / EVM hash, once submitted."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Client idempotency key when supplied via the Idempotency-Key header or body; null otherwise."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-03T12:01:00.000Z",
            "description": "Submit refuses the transaction after this; build a new swap."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          },
          "publicToken": {
            "type": "string",
            "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w",
            "description": "Only when the caller is the shared public key: this record’s read token. Send it as `X-Record-Token` on the routes of this one record. Reading it by id (and submitting a USDT0 transfer) answers 404 without it; swap submit and cross-chain deposit still accept a request without it for now, and will require it once the deployment turns `PUBLIC_RECORD_TOKEN_REQUIRED_ON_LEGACY` on. The same create replayed with its Idempotency-Key answers the same token. Keep it like the record id: whoever holds both can read the record."
          }
        },
        "description": "What `POST /v1/swaps` answers for a Solana or Monad swap: the swap and, for the shared public key, its read token.",
        "required": [
          "id",
          "chain",
          "network",
          "provider",
          "status",
          "source",
          "sendAsset",
          "sendAmount",
          "destAsset",
          "destEstimated",
          "destMin",
          "feeBps",
          "feeAmount",
          "slippageBps",
          "path",
          "transaction",
          "approval",
          "txHash",
          "idempotencyKey",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "ChainSwapEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm1x2y3z4a5b6c7d8e9f0g1h2",
            "description": "The swap's id."
          },
          "chain": {
            "type": "string",
            "enum": [
              "solana",
              "monad"
            ],
            "example": "solana",
            "description": "The chain the swap runs on."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always mainnet."
          },
          "provider": {
            "type": "string",
            "enum": [
              "jupiter",
              "kuru"
            ],
            "example": "jupiter",
            "description": "The aggregator that priced and built the swap: `jupiter` on Solana, `kuru` (Kuru Flow) on Monad."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "The swap's status: PENDING (built, not yet submitted), SUBMITTED (broadcast, awaiting the chain), SUCCEEDED, FAILED or EXPIRED."
          },
          "source": {
            "type": "string",
            "example": "13QkxhNMrTPxoCkRdYdJ65tFuwXPhL5gLS2Z5Nr6gjRK",
            "description": "The wallet that signs, pays and receives."
          },
          "sendAsset": {
            "type": "string",
            "example": "native",
            "description": "`native` (SOL / MON), or the SPL mint / ERC-20 address."
          },
          "sendAmount": {
            "type": "string",
            "example": "0.1",
            "description": "Gross amount of the sold asset, as a decimal string in its own units."
          },
          "destAsset": {
            "type": "string",
            "example": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
            "description": "The asset bought: `native` (SOL / MON), or the SPL mint / ERC-20 address."
          },
          "destEstimated": {
            "type": "string",
            "example": "11.87",
            "description": "Quoted output, net of the commission."
          },
          "destMin": {
            "type": "string",
            "example": "11.81",
            "description": "On-chain minimum after slippage."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points (50 = 0.5%), taken from the output."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.059",
            "description": "The commission, in the destination asset (taken from the output)."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "Slippage tolerance used to derive `destMin`, in basis points."
          },
          "path": {
            "description": "Intermediate assets of the route: SPL mints on Solana (with a null issuer); always empty on Monad.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SwapPathHop"
            }
          },
          "transaction": {
            "type": "object",
            "additionalProperties": true,
            "example": {
              "encoding": "base64",
              "data": "AQAAAAAAAAAAAAAAA…"
            },
            "description": "What the wallet signs. Solana: `{ encoding: \"base64\", data, lastValidBlockHeight }`, an unsigned VersionedTransaction. Monad: `{ to, data, value, chainId }`, a call the wallet signs as an EIP-1559 transaction (it fills nonce and gas)."
          },
          "approval": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "example": null,
            "description": "Monad only, selling an ERC-20 whose allowance is short: the exact `approve` call `{ to, data, value, chainId }` to send and confirm first. The wallet broadcasts it itself."
          },
          "txHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The Solana signature / EVM hash, once submitted."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Client idempotency key when supplied via the Idempotency-Key header or body; null otherwise."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-03T12:01:00.000Z",
            "description": "Submit refuses the transaction after this; build a new swap."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A Solana or Monad swap: built by Jupiter or Kuru Flow, signed by the wallet, relayed by this service. Returned by `/v1/swaps` when the request names `chain: solana | monad`.",
        "required": [
          "id",
          "chain",
          "network",
          "provider",
          "status",
          "source",
          "sendAsset",
          "sendAmount",
          "destAsset",
          "destEstimated",
          "destMin",
          "feeBps",
          "feeAmount",
          "slippageBps",
          "path",
          "transaction",
          "approval",
          "txHash",
          "idempotencyKey",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "ChainSwapListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "This page of swaps, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChainSwapEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "How many swaps match the filter, across every page."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "The page size used."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "How many swaps were skipped before this page."
          }
        },
        "description": "A page of Solana or Monad swaps, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "ChainSwapSubmitResultEntity": {
        "type": "object",
        "properties": {
          "submitted": {
            "type": "boolean",
            "example": true,
            "description": "Always true: the node accepted the broadcast. A refusal is a 400 `transaction_rejected` instead."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "SUBMITTED",
            "description": "The swap's status after the broadcast, normally SUBMITTED until the observer sees the transaction settle."
          },
          "txHash": {
            "type": "string",
            "example": "5VERv8NMvzbJMEkV8xnrLkEaWRtSz9CosKDYjCJjBRnbJLgp8uirBgmQpjKhoR4tjF3ZpRzrFmBV6UjKdiSZkQUW",
            "description": "The broadcast transaction: the Solana signature or the EVM transaction hash."
          },
          "swap": {
            "description": "The swap after the broadcast.",
            "allOf": [
              {
                "$ref": "#/components/schemas/ChainSwapEntity"
              }
            ]
          }
        },
        "description": "Result of `POST /v1/swaps/{id}/submit` for a Solana or Monad swap.",
        "required": [
          "submitted",
          "status",
          "txHash",
          "swap"
        ]
      },
      "SwapTrustline": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "USDC",
            "description": "Code of the asset the trustline is added for."
          },
          "issuer": {
            "type": "string",
            "example": "GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
            "description": "Issuer account of that asset."
          }
        },
        "description": "The asset a Stellar swap's transaction adds the source's trustline for, with a `changeTrust` as its first operation.",
        "required": [
          "code",
          "issuer"
        ]
      },
      "SwapCreatedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "The swap's id."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "The swap's status: PENDING (built, not yet submitted), SUBMITTED, SUCCEEDED, FAILED or EXPIRED."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The Stellar network the swap is on: `public` or `testnet`, following the API key."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The account that pays for and signs the swap (the transaction source)."
          },
          "destination": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The account credited the bought asset; equal to `source` for a self-swap."
          },
          "sendAsset": {
            "type": "string",
            "example": "native",
            "description": "The asset sold: its code, or `native` for XLM."
          },
          "sendAssetIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Issuer of the sold asset; null for native XLM."
          },
          "sendAmount": {
            "type": "string",
            "example": "100",
            "description": "Gross source amount."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.5",
            "description": "The plan commission, as a decimal string in the sold asset: `feeBps` of `sendAmount`, rounded down."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points (50 = 0.5%)."
          },
          "swapAmount": {
            "type": "string",
            "example": "99.5",
            "description": "Amount routed through the DEX/AMM."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee this swap pays, by its own payment in the same transaction; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "destAsset": {
            "type": "string",
            "example": "USDC",
            "description": "The asset bought: its code, or `native` for XLM."
          },
          "destAssetIssuer": {
            "type": "object",
            "nullable": true,
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6",
            "description": "Issuer of the bought asset; null for native XLM."
          },
          "destEstimated": {
            "type": "string",
            "example": "24.81",
            "description": "The quoted output at build time, as a decimal string in the bought asset."
          },
          "destMin": {
            "type": "string",
            "example": "24.68595",
            "description": "The on-chain minimum output after slippage (the path payment's destMin), as a decimal string: the swap reverts below it."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "Slippage tolerance used to derive `destMin`, in basis points."
          },
          "path": {
            "description": "Intermediate assets of the route; empty when it has none.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SwapPathHop"
            }
          },
          "memo": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The caller's MEMO_ID (numeric uint64) on the transaction; null when none was supplied."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": "swap-retry-2026-08-23-001",
            "description": "Client idempotency key when supplied via Idempotency-Key / body (null otherwise)."
          },
          "commissionMemo": {
            "type": "object",
            "nullable": true,
            "example": "Cosmos Swap Commission",
            "description": "On-chain MEMO_TEXT label stamped when a commission is collected and no caller memo was supplied (null otherwise)."
          },
          "trustline": {
            "nullable": true,
            "example": null,
            "description": "The bought asset, when the source receives it and does not trust it yet: the transaction then starts with a `changeTrust` for it, so the one signature adds the trustline and makes the swap. Adding it locks another 0.5 XLM base reserve in the account, which a wallet should tell its user before they sign. Null when no trustline is added (XLM bought, the account already trusts the asset, or the destination is another account). Read from the transaction itself.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/SwapTrustline"
              }
            ]
          },
          "xdr": {
            "type": "string",
            "description": "Unsigned transaction envelope (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "SEP-7 `web+stellar:tx` URI carrying `xdr`, for a wallet to open and sign."
          },
          "txHash": {
            "type": "string",
            "description": "Deterministic transaction hash (verified on submit).",
            "example": "3389e9f0...64hex"
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",
            "description": "PNG data URL of a QR code of `uri`."
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "description": "When the envelope's time bounds close; submit refuses it afterwards.",
            "example": "2026-06-29T12:39:56.000Z"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-29T12:34:56.000Z",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-29T12:34:56.000Z",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          },
          "publicToken": {
            "type": "string",
            "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w",
            "description": "Only when the caller is the shared public key: this record’s read token. Send it as `X-Record-Token` on the routes of this one record. Reading it by id (and submitting a USDT0 transfer) answers 404 without it; swap submit and cross-chain deposit still accept a request without it for now, and will require it once the deployment turns `PUBLIC_RECORD_TOKEN_REQUIRED_ON_LEGACY` on. The same create replayed with its Idempotency-Key answers the same token. Keep it like the record id: whoever holds both can read the record."
          }
        },
        "description": "What `POST /v1/swaps` answers for a Stellar swap: the swap and, for the shared public key, its read token.",
        "required": [
          "id",
          "status",
          "network",
          "source",
          "destination",
          "sendAsset",
          "sendAssetIssuer",
          "sendAmount",
          "feeAmount",
          "feeBps",
          "swapAmount",
          "merchantFee",
          "destAsset",
          "destAssetIssuer",
          "destEstimated",
          "destMin",
          "slippageBps",
          "path",
          "memo",
          "commissionMemo",
          "trustline",
          "xdr",
          "uri",
          "txHash",
          "qr",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "SwapEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "The swap's id."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "The swap's status: PENDING (built, not yet submitted), SUBMITTED, SUCCEEDED, FAILED or EXPIRED."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The Stellar network the swap is on: `public` or `testnet`, following the API key."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The account that pays for and signs the swap (the transaction source)."
          },
          "destination": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The account credited the bought asset; equal to `source` for a self-swap."
          },
          "sendAsset": {
            "type": "string",
            "example": "native",
            "description": "The asset sold: its code, or `native` for XLM."
          },
          "sendAssetIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Issuer of the sold asset; null for native XLM."
          },
          "sendAmount": {
            "type": "string",
            "example": "100",
            "description": "Gross source amount."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.5",
            "description": "The plan commission, as a decimal string in the sold asset: `feeBps` of `sendAmount`, rounded down."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points (50 = 0.5%)."
          },
          "swapAmount": {
            "type": "string",
            "example": "99.5",
            "description": "Amount routed through the DEX/AMM."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee this swap pays, by its own payment in the same transaction; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "destAsset": {
            "type": "string",
            "example": "USDC",
            "description": "The asset bought: its code, or `native` for XLM."
          },
          "destAssetIssuer": {
            "type": "object",
            "nullable": true,
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6",
            "description": "Issuer of the bought asset; null for native XLM."
          },
          "destEstimated": {
            "type": "string",
            "example": "24.81",
            "description": "The quoted output at build time, as a decimal string in the bought asset."
          },
          "destMin": {
            "type": "string",
            "example": "24.68595",
            "description": "The on-chain minimum output after slippage (the path payment's destMin), as a decimal string: the swap reverts below it."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "Slippage tolerance used to derive `destMin`, in basis points."
          },
          "path": {
            "description": "Intermediate assets of the route; empty when it has none.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SwapPathHop"
            }
          },
          "memo": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The caller's MEMO_ID (numeric uint64) on the transaction; null when none was supplied."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": "swap-retry-2026-08-23-001",
            "description": "Client idempotency key when supplied via Idempotency-Key / body (null otherwise)."
          },
          "commissionMemo": {
            "type": "object",
            "nullable": true,
            "example": "Cosmos Swap Commission",
            "description": "On-chain MEMO_TEXT label stamped when a commission is collected and no caller memo was supplied (null otherwise)."
          },
          "trustline": {
            "nullable": true,
            "example": null,
            "description": "The bought asset, when the source receives it and does not trust it yet: the transaction then starts with a `changeTrust` for it, so the one signature adds the trustline and makes the swap. Adding it locks another 0.5 XLM base reserve in the account, which a wallet should tell its user before they sign. Null when no trustline is added (XLM bought, the account already trusts the asset, or the destination is another account). Read from the transaction itself.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/SwapTrustline"
              }
            ]
          },
          "xdr": {
            "type": "string",
            "description": "Unsigned transaction envelope (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "SEP-7 `web+stellar:tx` URI carrying `xdr`, for a wallet to open and sign."
          },
          "txHash": {
            "type": "string",
            "description": "Deterministic transaction hash (verified on submit).",
            "example": "3389e9f0...64hex"
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",
            "description": "PNG data URL of a QR code of `uri`."
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "description": "When the envelope's time bounds close; submit refuses it afterwards.",
            "example": "2026-06-29T12:39:56.000Z"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-29T12:34:56.000Z",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-29T12:34:56.000Z",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A Stellar swap: the stored row with the unsigned transaction (base64 XDR, SEP-7 `uri` and QR) for `source` to sign.",
        "required": [
          "id",
          "status",
          "network",
          "source",
          "destination",
          "sendAsset",
          "sendAssetIssuer",
          "sendAmount",
          "feeAmount",
          "feeBps",
          "swapAmount",
          "merchantFee",
          "destAsset",
          "destAssetIssuer",
          "destEstimated",
          "destMin",
          "slippageBps",
          "path",
          "memo",
          "commissionMemo",
          "trustline",
          "xdr",
          "uri",
          "txHash",
          "qr",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "SwapListItemEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "The swap's id."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "The swap's status: PENDING (built, not yet submitted), SUBMITTED, SUCCEEDED, FAILED or EXPIRED."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The Stellar network the swap is on: `public` or `testnet`, following the API key."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The account that pays for and signs the swap (the transaction source)."
          },
          "destination": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The account credited the bought asset; equal to `source` for a self-swap."
          },
          "sendAsset": {
            "type": "string",
            "example": "native",
            "description": "The asset sold: its code, or `native` for XLM."
          },
          "sendAssetIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Issuer of the sold asset; null for native XLM."
          },
          "sendAmount": {
            "type": "string",
            "example": "100",
            "description": "Gross source amount."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.5",
            "description": "The plan commission, as a decimal string in the sold asset: `feeBps` of `sendAmount`, rounded down."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points (50 = 0.5%)."
          },
          "swapAmount": {
            "type": "string",
            "example": "99.5",
            "description": "Amount routed through the DEX/AMM."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee this swap pays, by its own payment in the same transaction; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "destAsset": {
            "type": "string",
            "example": "USDC",
            "description": "The asset bought: its code, or `native` for XLM."
          },
          "destAssetIssuer": {
            "type": "object",
            "nullable": true,
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6",
            "description": "Issuer of the bought asset; null for native XLM."
          },
          "destEstimated": {
            "type": "string",
            "example": "24.81",
            "description": "The quoted output at build time, as a decimal string in the bought asset."
          },
          "destMin": {
            "type": "string",
            "example": "24.68595",
            "description": "The on-chain minimum output after slippage (the path payment's destMin), as a decimal string: the swap reverts below it."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "Slippage tolerance used to derive `destMin`, in basis points."
          },
          "path": {
            "description": "Intermediate assets of the route; empty when it has none.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SwapPathHop"
            }
          },
          "memo": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The caller's MEMO_ID (numeric uint64) on the transaction; null when none was supplied."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": "swap-retry-2026-08-23-001",
            "description": "Client idempotency key when supplied via Idempotency-Key / body (null otherwise)."
          },
          "xdr": {
            "type": "string",
            "description": "Unsigned transaction envelope (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "SEP-7 `web+stellar:tx` URI carrying `xdr`, for a wallet to open and sign."
          },
          "txHash": {
            "type": "string",
            "description": "Deterministic transaction hash (verified on submit).",
            "example": "3389e9f0...64hex"
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "description": "When the envelope's time bounds close; submit refuses it afterwards.",
            "example": "2026-06-29T12:39:56.000Z"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-29T12:34:56.000Z",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-29T12:34:56.000Z",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A Stellar swap as `GET /v1/swaps` lists it: the stored row, without the QR, commission label and added trustline (read the swap by id for those).",
        "required": [
          "id",
          "status",
          "network",
          "source",
          "destination",
          "sendAsset",
          "sendAssetIssuer",
          "sendAmount",
          "feeAmount",
          "feeBps",
          "swapAmount",
          "merchantFee",
          "destAsset",
          "destAssetIssuer",
          "destEstimated",
          "destMin",
          "slippageBps",
          "path",
          "memo",
          "xdr",
          "uri",
          "txHash",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "SwapListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "This page of swaps, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SwapListItemEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "How many swaps match the filter, across every page."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "The page size used."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "How many swaps were skipped before this page."
          }
        },
        "description": "A page of Stellar swaps, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "SwapSubmitResultEntity": {
        "type": "object",
        "properties": {
          "submitted": {
            "type": "boolean",
            "example": true,
            "description": "True when the transaction settled (`status` SUCCEEDED); false when the network rejected this broadcast (see `reason`)."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "SUCCEEDED",
            "description": "The swap's status after the submit: SUCCEEDED, FAILED or SUBMITTED."
          },
          "txHash": {
            "type": "string",
            "nullable": true,
            "example": "3389e9f0...64hex",
            "description": "The on-chain transaction hash once submitted."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Why submission failed, when `submitted` is false. With `status` FAILED the ledger confirms the failure; with `status` SUBMITTED the network refused this broadcast but the transaction may still be on the ledger, and its outcome arrives as a terminal webhook."
          },
          "resultCodes": {
            "nullable": true,
            "example": [
              "op_under_dest_min"
            ],
            "description": "Horizon transaction/operation result codes on a rejection.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "swap": {
            "description": "The swap after the submit.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SwapEntity"
              }
            ]
          }
        },
        "description": "Result of `POST /v1/swaps/{id}/submit` for a Stellar swap.",
        "required": [
          "submitted",
          "status",
          "swap"
        ]
      },
      "QuoteSwapDto": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "The chain to swap on. Omitted means Stellar. solana → Jupiter, monad → Kuru Flow; both mainnet only. Swaps between chains are /v1/cross-chain-swaps."
          },
          "sourceAssetCode": {
            "type": "string",
            "description": "The asset being sold. Stellar: an asset code (native if omitted). Solana / Monad: SOL / MON, \"native\", or the mint / ERC-20 address.",
            "example": "XLM"
          },
          "sourceAssetIssuer": {
            "type": "string",
            "description": "Stellar only: issuer account for a non-native source asset.",
            "example": "GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB"
          },
          "amount": {
            "type": "string",
            "description": "Gross amount of the source asset to swap, in its own units (decimal; at most 7 places on Stellar, the token decimals elsewhere). Stellar deducts the platform fee from it; Solana and Monad take it from the output.",
            "example": "100"
          },
          "destAssetCode": {
            "type": "string",
            "description": "The asset being bought, spelled as for sourceAssetCode.",
            "example": "USDC"
          },
          "destAssetIssuer": {
            "type": "string",
            "description": "Stellar only: issuer account for the destination asset (required unless it is native).",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6"
          },
          "slippageBps": {
            "type": "number",
            "description": "Slippage tolerance in basis points (50 = 0.5%) used to derive the on-chain minimum received. Defaults to the service setting; capped by it.",
            "example": 50
          },
          "merchantFee": {
            "description": "Your own fee on this swap, paid in the source asset to `wallet` out of the source wallet, in the same transaction, beside the plan commission. Stellar: its own payment (the wallet must trust the asset). Solana: a transfer appended to Jupiter's transaction (a SOL fee goes to an existing account). `paidBy: recipient` takes it from `amount` (the swap routes less); `payer` adds it on top (the source sends `amount` plus the fee). Monad: through the merchant fee router (`KURU_MERCHANT_FEE_ROUTER`), which the wallet sends or approves the input plus the fee; without one configured, `merchant_fee_unsupported`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "A same-chain swap quote request: sell `amount` of the source asset for the destination asset on one chain (Stellar when `chain` is omitted).",
        "required": [
          "amount",
          "destAssetCode"
        ]
      },
      "SwapAssetAmount": {
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "example": "native",
            "description": "The asset. Stellar: its code, or `native` for XLM. Solana: `native` for SOL, or the SPL mint address. Monad: `native` for MON, or the ERC-20 contract address (EIP-55 checksummed)."
          },
          "issuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Issuer of a non-native Stellar asset; null for native XLM, and always null on Solana and Monad."
          },
          "amount": {
            "type": "string",
            "example": "100",
            "description": "The amount, as a decimal string in the asset's own units."
          }
        },
        "description": "An asset and an amount of it, as a swap quote reports the gross input and the amount routed.",
        "required": [
          "asset",
          "issuer",
          "amount"
        ]
      },
      "SwapFeeBreakdown": {
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "example": "native",
            "description": "The asset the commission is paid in: the source asset on Stellar, the bought asset on Solana and Monad."
          },
          "issuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Issuer of that asset when it is a non-native Stellar asset; null otherwise."
          },
          "amount": {
            "type": "string",
            "example": "0.5",
            "description": "The commission, as a decimal string in that asset's units."
          },
          "bps": {
            "type": "number",
            "example": 50,
            "description": "Fee in basis points (50 = 0.5%)."
          },
          "wallet": {
            "type": "object",
            "nullable": true,
            "example": "GBFEE...WALLET",
            "description": "Fee collector account (null when the fee is disabled)."
          },
          "label": {
            "type": "string",
            "example": "Cosmos Swap Commission",
            "description": "Human-readable commission label, mirrored as the on-chain MEMO_TEXT when the caller supplies no memo."
          }
        },
        "description": "The plan commission on a swap quote: taken from the source amount on Stellar, from the output on Solana and Monad.",
        "required": [
          "asset",
          "issuer",
          "amount",
          "bps",
          "wallet",
          "label"
        ]
      },
      "SwapDestinationQuote": {
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "example": "USDC",
            "description": "The asset bought: a Stellar asset code or `native`; on Solana and Monad, `native` or the mint / ERC-20 address."
          },
          "issuer": {
            "type": "object",
            "nullable": true,
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6",
            "description": "Issuer of a non-native Stellar asset; null for native XLM, and always null on Solana and Monad."
          },
          "estimated": {
            "type": "string",
            "example": "24.81",
            "description": "Quoted amount received for the routed (post-fee) input."
          },
          "minimum": {
            "type": "string",
            "example": "24.68595",
            "description": "On-chain minimum (destMin) after slippage: swap reverts below it."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "Slippage tolerance used for `minimum`, in basis points."
          }
        },
        "description": "The bought asset of a swap quote, with its estimated output and the slippage-protected minimum.",
        "required": [
          "asset",
          "issuer",
          "estimated",
          "minimum",
          "slippageBps"
        ]
      },
      "SwapQuoteEntity": {
        "type": "object",
        "properties": {
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The network the quote was priced on: `public` or `testnet` on Stellar, following the API key; always `public` on Solana and Monad."
          },
          "chain": {
            "type": "string",
            "enum": [
              "solana",
              "monad"
            ],
            "example": "solana",
            "description": "Solana and Monad quotes only. Absent on Stellar, which answers as it always has."
          },
          "provider": {
            "type": "string",
            "enum": [
              "jupiter",
              "kuru"
            ],
            "example": "jupiter",
            "description": "The aggregator that priced a Solana or Monad swap."
          },
          "source": {
            "description": "Gross source input.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SwapAssetAmount"
              }
            ]
          },
          "fee": {
            "description": "The plan commission: in the source asset on Stellar, in the bought asset on Solana and Monad.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SwapFeeBreakdown"
              }
            ]
          },
          "swap": {
            "description": "The amount routed, in the source asset. Stellar: `source.amount` less the plan commission (`fee.amount`) and less a merchant fee with `paidBy: recipient`. Solana and Monad: `source.amount` less a merchant fee with `paidBy: recipient`; the commission comes out of the output.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SwapAssetAmount"
              }
            ]
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee the request named, in the source asset; null without one. With `paidBy: payer` the source sends `source.amount` plus it.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "destination": {
            "description": "The bought asset, with the estimated output and the on-chain minimum.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SwapDestinationQuote"
              }
            ]
          },
          "path": {
            "description": "Intermediate hops (may be empty).",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SwapPathHop"
            }
          }
        },
        "description": "Response of `POST /v1/swaps/quote`: the price of a same-chain swap. Nothing is persisted.",
        "required": [
          "network",
          "source",
          "fee",
          "swap",
          "destination",
          "path"
        ]
      },
      "CreateSwapDto": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "The chain to swap on. Omitted means Stellar. solana → Jupiter, monad → Kuru Flow; both mainnet only. Swaps between chains are /v1/cross-chain-swaps."
          },
          "sourceAssetCode": {
            "type": "string",
            "description": "The asset being sold. Stellar: an asset code (native if omitted). Solana / Monad: SOL / MON, \"native\", or the mint / ERC-20 address.",
            "example": "XLM"
          },
          "sourceAssetIssuer": {
            "type": "string",
            "description": "Stellar only: issuer account for a non-native source asset.",
            "example": "GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB"
          },
          "amount": {
            "type": "string",
            "description": "Gross amount of the source asset to swap, in its own units (decimal; at most 7 places on Stellar, the token decimals elsewhere). Stellar deducts the platform fee from it; Solana and Monad take it from the output.",
            "example": "100"
          },
          "destAssetCode": {
            "type": "string",
            "description": "The asset being bought, spelled as for sourceAssetCode.",
            "example": "USDC"
          },
          "destAssetIssuer": {
            "type": "string",
            "description": "Stellar only: issuer account for the destination asset (required unless it is native).",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6"
          },
          "slippageBps": {
            "type": "number",
            "description": "Slippage tolerance in basis points (50 = 0.5%) used to derive the on-chain minimum received. Defaults to the service setting; capped by it.",
            "example": 50
          },
          "merchantFee": {
            "description": "Your own fee on this swap, paid in the source asset to `wallet` out of the source wallet, in the same transaction, beside the plan commission. Stellar: its own payment (the wallet must trust the asset). Solana: a transfer appended to Jupiter's transaction (a SOL fee goes to an existing account). `paidBy: recipient` takes it from `amount` (the swap routes less); `payer` adds it on top (the source sends `amount` plus the fee). Monad: through the merchant fee router (`KURU_MERCHANT_FEE_ROUTER`), which the wallet sends or approves the input plus the fee; without one configured, `merchant_fee_unsupported`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          },
          "source": {
            "type": "string",
            "description": "Account paying for (and signing) the swap (the tx source) on `chain`.",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"
          },
          "destination": {
            "type": "string",
            "description": "Account credited the destination asset. Defaults to `source` (a self-swap). On Stellar, when it is `source` and does not trust a non-native destination asset yet, the transaction adds that trustline first (see `trustline` on the response); any other account must already trust the asset, because only it can add the trustline. Stellar only: on Solana and Monad the output always goes to `source`.",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"
          },
          "memo": {
            "type": "string",
            "description": "Stellar only: optional MEMO_ID (numeric uint64) echoed on-chain for reconciliation.",
            "example": "123456789"
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Optional idempotency key. Prefer the `Idempotency-Key` request header; when both are set, the header wins. A retry with the same key and the same request returns the existing swap instead of building another transaction; the same key with a different request is 409 `idempotency_conflict`.",
            "example": "swap-retry-2026-08-23-001"
          }
        },
        "description": "A same-chain swap request: the quote fields plus the account that signs (`source`). The answer is the unsigned transaction for that account to sign.",
        "required": [
          "amount",
          "destAssetCode",
          "source"
        ]
      },
      "SubmitSwapDto": {
        "type": "object",
        "properties": {
          "signedXdr": {
            "type": "string",
            "description": "Stellar swaps: the signed transaction envelope (base64 XDR). Required unless signedTransaction is sent.",
            "example": "AAAAAgAAAABx…(signed base64 XDR)…AAAAAAAAAAA="
          },
          "signedTransaction": {
            "type": "string",
            "description": "Solana and Monad swaps: the signed transaction. Solana: base64 wire bytes of the VersionedTransaction; Monad: the 0x-hex raw EIP-1559 transaction (the eth_sendRawTransaction input).",
            "example": "0x02f8b1818f…"
          }
        },
        "description": "The signed swap transaction to relay: `signedXdr` for a Stellar swap, `signedTransaction` for a Solana or Monad swap. It must be the transaction built for this swap."
      },
      "CrossChainAssetEntity": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The network id a request names it by (originChain / destinationChain)."
          },
          "chainName": {
            "type": "string",
            "example": "Stellar",
            "description": "The network, by name: for display."
          },
          "symbol": {
            "type": "string",
            "example": "USDC",
            "description": "The token's symbol, as NEAR Intents lists it."
          },
          "assetId": {
            "type": "string",
            "example": "nep245:v2_1.omni.hot.tg:1100_111bzQBB65GxAPAVoxqmMcgYo5oS3txhqs1Uh1cgahKQUeTUq1TJu",
            "description": "NEAR Intents’ id for the asset."
          },
          "decimals": {
            "type": "number",
            "example": 7,
            "description": "The token's decimal places on its network, as NEAR Intents lists them."
          },
          "contract": {
            "type": "object",
            "nullable": true,
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
            "description": "The token on its network (SPL mint, ERC-20 address, Stellar issuer, Sui coin type, TON jetton master, ...); null for the native coin."
          },
          "priceUsd": {
            "type": "number",
            "nullable": true,
            "example": 0.999538,
            "description": "NEAR Intents’ reference price in USD, indicative only: for showing an estimate before a quote. It may be a few minutes old, and every amount still comes from a quote. Null when NEAR Intents lists none."
          }
        },
        "description": "A token NEAR Intents can swap, on one of the networks cross-chain swaps reach.",
        "required": [
          "chain",
          "chainName",
          "symbol",
          "assetId",
          "decimals",
          "contract",
          "priceUsd"
        ]
      },
      "CrossChainAssetListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "Every asset NEAR Intents still trades: a token it tags deprecated or lists with no price is left out.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainAssetEntity"
            }
          }
        },
        "description": "The assets cross-chain swaps can use, as `GET /v1/cross-chain-swaps/assets` lists them.",
        "required": [
          "data"
        ]
      },
      "QuoteCrossChainSwapDto": {
        "type": "object",
        "properties": {
          "originChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The network the payer deposits on: a `chain` from GET /v1/cross-chain-swaps/assets."
          },
          "originAsset": {
            "type": "string",
            "description": "The asset sold: \"native\" or the native ticker (XLM, SOL, ETH, BTC), a symbol listed once on the chain (USDC), a contract (SPL mint, ERC-20 address, Stellar issuer, ...) or Stellar CODE:ISSUER. See GET /v1/cross-chain-swaps/assets.",
            "example": "XLM"
          },
          "destinationChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "solana",
            "description": "The network the recipient is paid on."
          },
          "destinationAsset": {
            "type": "string",
            "description": "The asset bought, spelled as for originAsset.",
            "example": "USDC"
          },
          "amount": {
            "type": "string",
            "description": "Gross amount of the origin asset, in its own units (decimal). The plan commission is taken out of it; the quoted output is net of it.",
            "example": "100"
          },
          "recipient": {
            "type": "string",
            "description": "Who receives the output, on destinationChain.",
            "example": "13QkxhNMrTPxoCkRdYdJ65tFuwXPhL5gLS2Z5Nr6gjRK"
          },
          "refundTo": {
            "type": "string",
            "description": "Where a failed or late deposit is refunded, on originChain: normally the paying wallet.",
            "example": "GCKFBEIYV2U22IO2BJ4KVJOIP7XPWQGQFKKWXR6DOSJBV7STMAQSMTGG"
          },
          "slippageBps": {
            "type": "number",
            "description": "Slippage tolerance in basis points (100 = 1%). Below the resulting minimum, NEAR Intents refunds instead of filling. Defaults to the service setting; capped by it.",
            "example": 100
          },
          "merchantFee": {
            "description": "Your own fee on this swap, which NEAR Intents pays as a second app fee to `wallet`: a NEAR account id (named, e.g. merchant.near, or 64-hex implicit), credited inside NEAR Intents. App fees are whole basis points of the deposit, so the fee is turned into the basis points it amounts to, rounded down. `paidBy: recipient` takes it from `amount` (the deposit stays `amount`); `payer` adds it to the deposit.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "A cross-chain swap quote request: sell `amount` of `originAsset` on `originChain` for `destinationAsset` on `destinationChain`, paid to `recipient`. NEAR Intents prices it; a failed swap refunds `refundTo`.",
        "required": [
          "originChain",
          "originAsset",
          "destinationChain",
          "destinationAsset",
          "amount",
          "recipient",
          "refundTo"
        ]
      },
      "CrossChainQuoteLeg": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The leg's network id."
          },
          "asset": {
            "type": "string",
            "example": "XLM",
            "description": "The asset's symbol, as NEAR Intents lists it."
          },
          "assetId": {
            "type": "string",
            "example": "nep245:v2_1.omni.hot.tg:1100_111bzQBB5v7AhLyPMDwS8uJgQV24KaAPXtwyVWu2KXbbfQU6NXRCz",
            "description": "NEAR Intents' id for the asset."
          },
          "contract": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The token's contract on its network; null for the native coin."
          },
          "amount": {
            "type": "string",
            "example": "100",
            "description": "Origin: the gross amount sent. Destination: the quoted amount received, net of every fee."
          },
          "amountUsd": {
            "type": "object",
            "nullable": true,
            "example": "22.57",
            "description": "NEAR Intents’ USD valuation, informational only."
          }
        },
        "description": "One leg of a cross-chain swap quote: an asset on one network and its amount.",
        "required": [
          "chain",
          "asset",
          "assetId",
          "contract",
          "amount",
          "amountUsd"
        ]
      },
      "CrossChainQuoteDestination": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The leg's network id."
          },
          "asset": {
            "type": "string",
            "example": "XLM",
            "description": "The asset's symbol, as NEAR Intents lists it."
          },
          "assetId": {
            "type": "string",
            "example": "nep245:v2_1.omni.hot.tg:1100_111bzQBB5v7AhLyPMDwS8uJgQV24KaAPXtwyVWu2KXbbfQU6NXRCz",
            "description": "NEAR Intents' id for the asset."
          },
          "contract": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The token's contract on its network; null for the native coin."
          },
          "amount": {
            "type": "string",
            "example": "100",
            "description": "Origin: the gross amount sent. Destination: the quoted amount received, net of every fee."
          },
          "amountUsd": {
            "type": "object",
            "nullable": true,
            "example": "22.57",
            "description": "NEAR Intents’ USD valuation, informational only."
          },
          "minimum": {
            "type": "string",
            "example": "21.967571",
            "description": "Minimum output after slippage; below it the swap is refunded."
          }
        },
        "description": "The destination leg of a cross-chain swap quote, with the minimum output below which NEAR Intents refunds.",
        "required": [
          "chain",
          "asset",
          "assetId",
          "contract",
          "amount",
          "amountUsd",
          "minimum"
        ]
      },
      "CrossChainFeeEntity": {
        "type": "object",
        "properties": {
          "bps": {
            "type": "number",
            "example": 50,
            "description": "Basis points of the input."
          },
          "amount": {
            "type": "string",
            "example": "0.5",
            "description": "In the origin asset."
          },
          "asset": {
            "type": "string",
            "example": "XLM",
            "description": "The origin asset's symbol: the commission is paid in it."
          }
        },
        "description": "The plan commission on a cross-chain swap, which NEAR Intents takes out of the input as an app fee.",
        "required": [
          "bps",
          "amount",
          "asset"
        ]
      },
      "CrossChainQuoteEntity": {
        "type": "object",
        "properties": {
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always public: NEAR Intents prices and settles on mainnet."
          },
          "origin": {
            "description": "The origin leg: what the payer deposits.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CrossChainQuoteLeg"
              }
            ]
          },
          "destination": {
            "description": "The destination leg: what the recipient receives, with its minimum.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CrossChainQuoteDestination"
              }
            ]
          },
          "fee": {
            "description": "The plan commission, in the origin asset.",
            "allOf": [
              {
                "$ref": "#/components/schemas/CrossChainFeeEntity"
              }
            ]
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee NEAR Intents will pay, in the origin asset; null without one.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "slippageBps": {
            "type": "number",
            "example": 100,
            "description": "Slippage tolerance used for the destination minimum, in basis points (100 = 1%)."
          },
          "timeEstimateSeconds": {
            "type": "number",
            "example": 22,
            "description": "NEAR Intents’ estimate, in seconds after the deposit confirms."
          }
        },
        "description": "Response of `POST /v1/cross-chain-swaps/quote`: the price of a cross-chain swap through NEAR Intents. Nothing is persisted.",
        "required": [
          "network",
          "origin",
          "destination",
          "fee",
          "merchantFee",
          "slippageBps",
          "timeEstimateSeconds"
        ]
      },
      "CreateCrossChainSwapDto": {
        "type": "object",
        "properties": {
          "originChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The network the payer deposits on: a `chain` from GET /v1/cross-chain-swaps/assets."
          },
          "originAsset": {
            "type": "string",
            "description": "The asset sold: \"native\" or the native ticker (XLM, SOL, ETH, BTC), a symbol listed once on the chain (USDC), a contract (SPL mint, ERC-20 address, Stellar issuer, ...) or Stellar CODE:ISSUER. See GET /v1/cross-chain-swaps/assets.",
            "example": "XLM"
          },
          "destinationChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "solana",
            "description": "The network the recipient is paid on."
          },
          "destinationAsset": {
            "type": "string",
            "description": "The asset bought, spelled as for originAsset.",
            "example": "USDC"
          },
          "amount": {
            "type": "string",
            "description": "Gross amount of the origin asset, in its own units (decimal). The plan commission is taken out of it; the quoted output is net of it.",
            "example": "100"
          },
          "recipient": {
            "type": "string",
            "description": "Who receives the output, on destinationChain.",
            "example": "13QkxhNMrTPxoCkRdYdJ65tFuwXPhL5gLS2Z5Nr6gjRK"
          },
          "refundTo": {
            "type": "string",
            "description": "Where a failed or late deposit is refunded, on originChain: normally the paying wallet.",
            "example": "GCKFBEIYV2U22IO2BJ4KVJOIP7XPWQGQFKKWXR6DOSJBV7STMAQSMTGG"
          },
          "slippageBps": {
            "type": "number",
            "description": "Slippage tolerance in basis points (100 = 1%). Below the resulting minimum, NEAR Intents refunds instead of filling. Defaults to the service setting; capped by it.",
            "example": 100
          },
          "merchantFee": {
            "description": "Your own fee on this swap, which NEAR Intents pays as a second app fee to `wallet`: a NEAR account id (named, e.g. merchant.near, or 64-hex implicit), credited inside NEAR Intents. App fees are whole basis points of the deposit, so the fee is turned into the basis points it amounts to, rounded down. `paidBy: recipient` takes it from `amount` (the deposit stays `amount`); `payer` adds it to the deposit.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Idempotency key. The Idempotency-Key header takes precedence over this field.",
            "example": "xswap-2026-10-02-001"
          }
        },
        "description": "A cross-chain swap request: the quote fields plus an optional idempotency key. The answer carries a NEAR Intents deposit address to pay.",
        "required": [
          "originChain",
          "originAsset",
          "destinationChain",
          "destinationAsset",
          "amount",
          "recipient",
          "refundTo"
        ]
      },
      "CrossChainTransactionEntity": {
        "type": "object",
        "properties": {
          "hash": {
            "type": "string",
            "example": "0x9a…",
            "description": "The transaction id on its chain, as NEAR Intents reports it."
          },
          "explorerUrl": {
            "type": "string",
            "example": "https://solscan.io/tx/…",
            "description": "A block explorer link to the transaction, as NEAR Intents reports it."
          }
        },
        "description": "A settlement transaction NEAR Intents reports, with its explorer link.",
        "required": [
          "hash",
          "explorerUrl"
        ]
      },
      "CrossChainSwapCreatedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm1x2y3z4a5b6c7d8e9f0g1h2",
            "description": "The swap's id."
          },
          "status": {
            "type": "string",
            "enum": [
              "AWAITING_DEPOSIT",
              "DEPOSIT_DETECTED",
              "INCOMPLETE_DEPOSIT",
              "PROCESSING",
              "SUCCEEDED",
              "REFUNDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "AWAITING_DEPOSIT",
            "description": "The swap's status, mapped from NEAR Intents' `providerStatus`; EXPIRED means the deadline passed with nothing deposited."
          },
          "providerStatus": {
            "type": "string",
            "example": "PENDING_DEPOSIT",
            "description": "NEAR Intents’ own status word, verbatim."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always `public`: NEAR Intents settles on mainnet only."
          },
          "originChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The network the payer deposits on."
          },
          "originAsset": {
            "type": "string",
            "example": "XLM",
            "description": "The sold asset's symbol, as NEAR Intents lists it."
          },
          "originContract": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The sold token's contract on its network; null for the native coin."
          },
          "destinationChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "solana",
            "description": "The network the recipient is paid on."
          },
          "destinationAsset": {
            "type": "string",
            "example": "USDC",
            "description": "The bought asset's symbol, as NEAR Intents lists it."
          },
          "destinationContract": {
            "type": "object",
            "nullable": true,
            "example": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
            "description": "The bought token's contract on its network; null for the native coin."
          },
          "amountIn": {
            "type": "string",
            "example": "100",
            "description": "Gross, in the origin asset."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points of `amountIn`."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.5",
            "description": "The plan commission, as a decimal string in the origin asset, which NEAR Intents takes as an app fee."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee NEAR Intents pays as an app fee; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "amountOutEstimated": {
            "type": "string",
            "example": "22.189466",
            "description": "The quoted output, as a decimal string in the destination asset, net of the commission."
          },
          "amountOutMin": {
            "type": "string",
            "example": "21.967571",
            "description": "Minimum output after slippage, as a decimal string in the destination asset; below it the swap is refunded."
          },
          "slippageBps": {
            "type": "number",
            "example": 100,
            "description": "Slippage tolerance used to derive `amountOutMin`, in basis points."
          },
          "recipient": {
            "type": "string",
            "example": "13QkxhNMrTPxoCkRdYdJ65tFuwXPhL5gLS2Z5Nr6gjRK",
            "description": "Who receives the output, on `destinationChain`."
          },
          "refundTo": {
            "type": "string",
            "example": "GCKFBEIYV2U22IO2BJ4KVJOIP7XPWQGQFKKWXR6DOSJBV7STMAQSMTGG",
            "description": "Where a failed or late deposit is refunded, on `originChain`."
          },
          "depositAddress": {
            "type": "string",
            "example": "GDJ4JZXZELZD737NVFORH4PSSQDWFDZTKW3AIDKHYQG23ZXBPDGGQBJK",
            "description": "Send exactly amountIn of the origin asset here."
          },
          "depositMemo": {
            "type": "object",
            "nullable": true,
            "example": "188866795",
            "description": "Required whenever it is set: attach it to the deposit or the deposit is lost to the swap. Always set on Stellar (a MEMO_TEXT); on another chain only if NEAR Intents issues one."
          },
          "depositUri": {
            "type": "string",
            "nullable": true,
            "example": "web+stellar:pay?destination=GDJ4…&amount=100&memo=188866795&memo_type=MEMO_TEXT",
            "description": "The deposit as a wallet link on the origin chain, where the chain has a wallet-link standard: SEP-7 pay, Solana Pay, EIP-681, BIP-21 style (bitcoin:, litecoin:, dogecoin:, bitcoincash:, dash:, zcash:), ton:// transfer or CIP-13 web+cardano:. Null means: pay depositAddress (and depositMemo, if set) with any wallet of that chain."
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgo…",
            "description": "PNG data URL of a QR code: of depositUri when there is one, else of depositAddress."
          },
          "depositTxHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The deposit transaction reported through `POST /v1/cross-chain-swaps/{id}/deposit`; null until one is reported."
          },
          "amountOut": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Settled output, once NEAR Intents reports it."
          },
          "refundedAmount": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The amount refunded to `refundTo`, as a decimal string in the origin asset, once NEAR Intents reports a refund; null otherwise."
          },
          "originTxHashes": {
            "nullable": true,
            "description": "Transactions NEAR Intents reports on the origin chain; null until it reports any.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainTransactionEntity"
            }
          },
          "destinationTxHashes": {
            "nullable": true,
            "description": "Transactions NEAR Intents reports on the destination chain; null until it reports any.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainTransactionEntity"
            }
          },
          "timeEstimateSeconds": {
            "type": "number",
            "example": 22,
            "description": "NEAR Intents' estimate, in seconds after the deposit confirms."
          },
          "correlationId": {
            "type": "string",
            "example": "c5928abd-243c-4019-aebd-6cccc185cc96",
            "description": "NEAR Intents’ id for the quote, for support requests."
          },
          "quoteSignature": {
            "type": "string",
            "example": "ed25519:Ze6U5JbqTTbXNvU5PW2g…",
            "description": "NEAR Intents’ signature over the quote and deposit address. Keep it: it settles a dispute."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Client idempotency key when supplied via the Idempotency-Key header or body; null otherwise."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-02T12:30:00.000Z",
            "description": "After this the deposit address refunds whatever arrives."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          },
          "publicToken": {
            "type": "string",
            "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w",
            "description": "Only when the caller is the shared public key: this record’s read token. Send it as `X-Record-Token` on the routes of this one record. Reading it by id (and submitting a USDT0 transfer) answers 404 without it; swap submit and cross-chain deposit still accept a request without it for now, and will require it once the deployment turns `PUBLIC_RECORD_TOKEN_REQUIRED_ON_LEGACY` on. The same create replayed with its Idempotency-Key answers the same token. Keep it like the record id: whoever holds both can read the record."
          }
        },
        "description": "What `POST /v1/cross-chain-swaps` answers: the swap and, for the shared public key, its read token.",
        "required": [
          "id",
          "status",
          "providerStatus",
          "network",
          "originChain",
          "originAsset",
          "originContract",
          "destinationChain",
          "destinationAsset",
          "destinationContract",
          "amountIn",
          "feeBps",
          "feeAmount",
          "merchantFee",
          "amountOutEstimated",
          "amountOutMin",
          "slippageBps",
          "recipient",
          "refundTo",
          "depositAddress",
          "depositMemo",
          "depositUri",
          "qr",
          "depositTxHash",
          "amountOut",
          "refundedAmount",
          "originTxHashes",
          "destinationTxHashes",
          "timeEstimateSeconds",
          "correlationId",
          "quoteSignature",
          "idempotencyKey",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "CrossChainSwapListItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm1x2y3z4a5b6c7d8e9f0g1h2",
            "description": "The swap's id."
          },
          "status": {
            "type": "string",
            "enum": [
              "AWAITING_DEPOSIT",
              "DEPOSIT_DETECTED",
              "INCOMPLETE_DEPOSIT",
              "PROCESSING",
              "SUCCEEDED",
              "REFUNDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "AWAITING_DEPOSIT",
            "description": "The swap's status, mapped from NEAR Intents' `providerStatus`; EXPIRED means the deadline passed with nothing deposited."
          },
          "providerStatus": {
            "type": "string",
            "example": "PENDING_DEPOSIT",
            "description": "NEAR Intents’ own status word, verbatim."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always `public`: NEAR Intents settles on mainnet only."
          },
          "originChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The network the payer deposits on."
          },
          "originAsset": {
            "type": "string",
            "example": "XLM",
            "description": "The sold asset's symbol, as NEAR Intents lists it."
          },
          "originContract": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The sold token's contract on its network; null for the native coin."
          },
          "destinationChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "solana",
            "description": "The network the recipient is paid on."
          },
          "destinationAsset": {
            "type": "string",
            "example": "USDC",
            "description": "The bought asset's symbol, as NEAR Intents lists it."
          },
          "destinationContract": {
            "type": "object",
            "nullable": true,
            "example": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
            "description": "The bought token's contract on its network; null for the native coin."
          },
          "amountIn": {
            "type": "string",
            "example": "100",
            "description": "Gross, in the origin asset."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points of `amountIn`."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.5",
            "description": "The plan commission, as a decimal string in the origin asset, which NEAR Intents takes as an app fee."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee NEAR Intents pays as an app fee; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "amountOutEstimated": {
            "type": "string",
            "example": "22.189466",
            "description": "The quoted output, as a decimal string in the destination asset, net of the commission."
          },
          "amountOutMin": {
            "type": "string",
            "example": "21.967571",
            "description": "Minimum output after slippage, as a decimal string in the destination asset; below it the swap is refunded."
          },
          "slippageBps": {
            "type": "number",
            "example": 100,
            "description": "Slippage tolerance used to derive `amountOutMin`, in basis points."
          },
          "recipient": {
            "type": "string",
            "example": "13QkxhNMrTPxoCkRdYdJ65tFuwXPhL5gLS2Z5Nr6gjRK",
            "description": "Who receives the output, on `destinationChain`."
          },
          "refundTo": {
            "type": "string",
            "example": "GCKFBEIYV2U22IO2BJ4KVJOIP7XPWQGQFKKWXR6DOSJBV7STMAQSMTGG",
            "description": "Where a failed or late deposit is refunded, on `originChain`."
          },
          "depositAddress": {
            "type": "string",
            "example": "GDJ4JZXZELZD737NVFORH4PSSQDWFDZTKW3AIDKHYQG23ZXBPDGGQBJK",
            "description": "Send exactly amountIn of the origin asset here."
          },
          "depositMemo": {
            "type": "object",
            "nullable": true,
            "example": "188866795",
            "description": "Required whenever it is set: attach it to the deposit or the deposit is lost to the swap. Always set on Stellar (a MEMO_TEXT); on another chain only if NEAR Intents issues one."
          },
          "depositUri": {
            "type": "string",
            "nullable": true,
            "example": "web+stellar:pay?destination=GDJ4…&amount=100&memo=188866795&memo_type=MEMO_TEXT",
            "description": "The deposit as a wallet link on the origin chain, where the chain has a wallet-link standard: SEP-7 pay, Solana Pay, EIP-681, BIP-21 style (bitcoin:, litecoin:, dogecoin:, bitcoincash:, dash:, zcash:), ton:// transfer or CIP-13 web+cardano:. Null means: pay depositAddress (and depositMemo, if set) with any wallet of that chain."
          },
          "depositTxHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The deposit transaction reported through `POST /v1/cross-chain-swaps/{id}/deposit`; null until one is reported."
          },
          "amountOut": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Settled output, once NEAR Intents reports it."
          },
          "refundedAmount": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The amount refunded to `refundTo`, as a decimal string in the origin asset, once NEAR Intents reports a refund; null otherwise."
          },
          "originTxHashes": {
            "nullable": true,
            "description": "Transactions NEAR Intents reports on the origin chain; null until it reports any.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainTransactionEntity"
            }
          },
          "destinationTxHashes": {
            "nullable": true,
            "description": "Transactions NEAR Intents reports on the destination chain; null until it reports any.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainTransactionEntity"
            }
          },
          "timeEstimateSeconds": {
            "type": "number",
            "example": 22,
            "description": "NEAR Intents' estimate, in seconds after the deposit confirms."
          },
          "correlationId": {
            "type": "string",
            "example": "c5928abd-243c-4019-aebd-6cccc185cc96",
            "description": "NEAR Intents’ id for the quote, for support requests."
          },
          "quoteSignature": {
            "type": "string",
            "example": "ed25519:Ze6U5JbqTTbXNvU5PW2g…",
            "description": "NEAR Intents’ signature over the quote and deposit address. Keep it: it settles a dispute."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Client idempotency key when supplied via the Idempotency-Key header or body; null otherwise."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-02T12:30:00.000Z",
            "description": "After this the deposit address refunds whatever arrives."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A cross-chain swap as `GET /v1/cross-chain-swaps` lists it: the stored row, without the QR.",
        "required": [
          "id",
          "status",
          "providerStatus",
          "network",
          "originChain",
          "originAsset",
          "originContract",
          "destinationChain",
          "destinationAsset",
          "destinationContract",
          "amountIn",
          "feeBps",
          "feeAmount",
          "merchantFee",
          "amountOutEstimated",
          "amountOutMin",
          "slippageBps",
          "recipient",
          "refundTo",
          "depositAddress",
          "depositMemo",
          "depositUri",
          "depositTxHash",
          "amountOut",
          "refundedAmount",
          "originTxHashes",
          "destinationTxHashes",
          "timeEstimateSeconds",
          "correlationId",
          "quoteSignature",
          "idempotencyKey",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "CrossChainSwapListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "This page of swaps, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainSwapListItem"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "How many swaps match the filter, across every page."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "The page size used."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "How many swaps were skipped before this page."
          }
        },
        "description": "A page of cross-chain swaps, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "CrossChainSwapEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm1x2y3z4a5b6c7d8e9f0g1h2",
            "description": "The swap's id."
          },
          "status": {
            "type": "string",
            "enum": [
              "AWAITING_DEPOSIT",
              "DEPOSIT_DETECTED",
              "INCOMPLETE_DEPOSIT",
              "PROCESSING",
              "SUCCEEDED",
              "REFUNDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "AWAITING_DEPOSIT",
            "description": "The swap's status, mapped from NEAR Intents' `providerStatus`; EXPIRED means the deadline passed with nothing deposited."
          },
          "providerStatus": {
            "type": "string",
            "example": "PENDING_DEPOSIT",
            "description": "NEAR Intents’ own status word, verbatim."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always `public`: NEAR Intents settles on mainnet only."
          },
          "originChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "stellar",
            "description": "The network the payer deposits on."
          },
          "originAsset": {
            "type": "string",
            "example": "XLM",
            "description": "The sold asset's symbol, as NEAR Intents lists it."
          },
          "originContract": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The sold token's contract on its network; null for the native coin."
          },
          "destinationChain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad",
              "eth",
              "base",
              "arb",
              "op",
              "bsc",
              "pol",
              "avax",
              "gnosis",
              "bera",
              "scroll",
              "xlayer",
              "abs",
              "plasma",
              "hood",
              "hypercore",
              "btc",
              "ltc",
              "doge",
              "bch",
              "dash",
              "zec",
              "xrp",
              "tron",
              "ton",
              "near",
              "sui",
              "aptos",
              "movement",
              "starknet",
              "cardano",
              "aleo",
              "fogo"
            ],
            "example": "solana",
            "description": "The network the recipient is paid on."
          },
          "destinationAsset": {
            "type": "string",
            "example": "USDC",
            "description": "The bought asset's symbol, as NEAR Intents lists it."
          },
          "destinationContract": {
            "type": "object",
            "nullable": true,
            "example": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
            "description": "The bought token's contract on its network; null for the native coin."
          },
          "amountIn": {
            "type": "string",
            "example": "100",
            "description": "Gross, in the origin asset."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "The plan commission rate, in basis points of `amountIn`."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.5",
            "description": "The plan commission, as a decimal string in the origin asset, which NEAR Intents takes as an app fee."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee NEAR Intents pays as an app fee; null when the request named none.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "amountOutEstimated": {
            "type": "string",
            "example": "22.189466",
            "description": "The quoted output, as a decimal string in the destination asset, net of the commission."
          },
          "amountOutMin": {
            "type": "string",
            "example": "21.967571",
            "description": "Minimum output after slippage, as a decimal string in the destination asset; below it the swap is refunded."
          },
          "slippageBps": {
            "type": "number",
            "example": 100,
            "description": "Slippage tolerance used to derive `amountOutMin`, in basis points."
          },
          "recipient": {
            "type": "string",
            "example": "13QkxhNMrTPxoCkRdYdJ65tFuwXPhL5gLS2Z5Nr6gjRK",
            "description": "Who receives the output, on `destinationChain`."
          },
          "refundTo": {
            "type": "string",
            "example": "GCKFBEIYV2U22IO2BJ4KVJOIP7XPWQGQFKKWXR6DOSJBV7STMAQSMTGG",
            "description": "Where a failed or late deposit is refunded, on `originChain`."
          },
          "depositAddress": {
            "type": "string",
            "example": "GDJ4JZXZELZD737NVFORH4PSSQDWFDZTKW3AIDKHYQG23ZXBPDGGQBJK",
            "description": "Send exactly amountIn of the origin asset here."
          },
          "depositMemo": {
            "type": "object",
            "nullable": true,
            "example": "188866795",
            "description": "Required whenever it is set: attach it to the deposit or the deposit is lost to the swap. Always set on Stellar (a MEMO_TEXT); on another chain only if NEAR Intents issues one."
          },
          "depositUri": {
            "type": "string",
            "nullable": true,
            "example": "web+stellar:pay?destination=GDJ4…&amount=100&memo=188866795&memo_type=MEMO_TEXT",
            "description": "The deposit as a wallet link on the origin chain, where the chain has a wallet-link standard: SEP-7 pay, Solana Pay, EIP-681, BIP-21 style (bitcoin:, litecoin:, dogecoin:, bitcoincash:, dash:, zcash:), ton:// transfer or CIP-13 web+cardano:. Null means: pay depositAddress (and depositMemo, if set) with any wallet of that chain."
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgo…",
            "description": "PNG data URL of a QR code: of depositUri when there is one, else of depositAddress."
          },
          "depositTxHash": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The deposit transaction reported through `POST /v1/cross-chain-swaps/{id}/deposit`; null until one is reported."
          },
          "amountOut": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Settled output, once NEAR Intents reports it."
          },
          "refundedAmount": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The amount refunded to `refundTo`, as a decimal string in the origin asset, once NEAR Intents reports a refund; null otherwise."
          },
          "originTxHashes": {
            "nullable": true,
            "description": "Transactions NEAR Intents reports on the origin chain; null until it reports any.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainTransactionEntity"
            }
          },
          "destinationTxHashes": {
            "nullable": true,
            "description": "Transactions NEAR Intents reports on the destination chain; null until it reports any.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CrossChainTransactionEntity"
            }
          },
          "timeEstimateSeconds": {
            "type": "number",
            "example": 22,
            "description": "NEAR Intents' estimate, in seconds after the deposit confirms."
          },
          "correlationId": {
            "type": "string",
            "example": "c5928abd-243c-4019-aebd-6cccc185cc96",
            "description": "NEAR Intents’ id for the quote, for support requests."
          },
          "quoteSignature": {
            "type": "string",
            "example": "ed25519:Ze6U5JbqTTbXNvU5PW2g…",
            "description": "NEAR Intents’ signature over the quote and deposit address. Keep it: it settles a dispute."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Client idempotency key when supplied via the Idempotency-Key header or body; null otherwise."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-02T12:30:00.000Z",
            "description": "After this the deposit address refunds whatever arrives."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was created (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the swap was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A cross-chain swap settled by NEAR Intents: the deposit request the payer pays, and the settlement as NEAR Intents reports it.",
        "required": [
          "id",
          "status",
          "providerStatus",
          "network",
          "originChain",
          "originAsset",
          "originContract",
          "destinationChain",
          "destinationAsset",
          "destinationContract",
          "amountIn",
          "feeBps",
          "feeAmount",
          "merchantFee",
          "amountOutEstimated",
          "amountOutMin",
          "slippageBps",
          "recipient",
          "refundTo",
          "depositAddress",
          "depositMemo",
          "depositUri",
          "qr",
          "depositTxHash",
          "amountOut",
          "refundedAmount",
          "originTxHashes",
          "destinationTxHashes",
          "timeEstimateSeconds",
          "correlationId",
          "quoteSignature",
          "idempotencyKey",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "SubmitDepositDto": {
        "type": "object",
        "properties": {
          "txHash": {
            "type": "string",
            "description": "The transaction that paid the deposit address, in the origin chain's own spelling: a 64-hex hash on Stellar and the UTXO chains, 0x + 64 hex on EVM networks, a base58 signature on Solana. A 400 names the shape the origin chain expects.",
            "example": "5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a"
          }
        },
        "description": "Reports the transaction that paid a cross-chain swap's deposit address, so NEAR Intents can start the swap without waiting for its indexer.",
        "required": [
          "txHash"
        ]
      },
      "DepositLiquidityDto": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "Account funding (and signing) the deposit: the tx source.",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"
          },
          "assetACode": {
            "type": "string",
            "description": "First asset of the pair. Native if omitted.",
            "example": "XLM"
          },
          "assetAIssuer": {
            "type": "string",
            "description": "Issuer account for a non-native first asset.",
            "example": "GCRCUE2C5TBNIPYHMEP7NK5RWTT2WBSZ75CMARH7GDOHDDCQH3XANFOB"
          },
          "assetBCode": {
            "type": "string",
            "description": "Second asset of the pair. Native if omitted.",
            "example": "USDC"
          },
          "assetBIssuer": {
            "type": "string",
            "description": "Issuer account for a non-native second asset.",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6"
          },
          "maxAmountA": {
            "type": "string",
            "description": "Maximum amount of the first asset to deposit (decimal, ≤ 7 places).",
            "example": "1000"
          },
          "maxAmountB": {
            "type": "string",
            "description": "Maximum amount of the second asset. When the pool already has reserves this is derived from the pool price if omitted; it is required when the pool is new or empty (the deposit sets the price).",
            "example": "100"
          },
          "slippageBps": {
            "type": "number",
            "description": "Slippage tolerance in basis points (50 = 0.5%) used to derive the on-chain min/max price bounds. Defaults to the service setting; capped by it.",
            "example": 50
          },
          "memo": {
            "type": "string",
            "description": "Optional MEMO_ID (numeric uint64) echoed on-chain for reconciliation.",
            "example": "123456789"
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Optional idempotency key. Prefer the `Idempotency-Key` request header; when both are set, the header wins. A retry with the same key and the same request returns the existing operation instead of building another transaction; the same key with a different request is 409 `idempotency_conflict`.",
            "example": "lp-deposit-2026-08-23-001"
          },
          "merchantFee": {
            "description": "Your own fee on this deposit: `bps` of EACH asset it moves, paid to `wallet` (a Stellar account that can receive both assets) by one payment per asset in the same transaction, beside the plan commission. `fixed` is refused here: the operation moves two assets. `paidBy: recipient` takes it from the amounts (less enters the pool); `payer` adds it on top (the full amounts enter the pool).",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "A liquidity pool deposit request. The pair may be given in either order: the service reorders it, and its amounts, into the protocol's canonical order.",
        "required": [
          "source",
          "maxAmountA"
        ]
      },
      "LiquidityMerchantFeeEntity": {
        "type": "object",
        "properties": {
          "bps": {
            "type": "number",
            "description": "The percentage part, in basis points.",
            "example": 150
          },
          "fixed": {
            "type": "string",
            "description": "The fixed part, in `asset`.",
            "example": "0.25"
          },
          "amount": {
            "type": "string",
            "description": "The fee charged: the percentage of `amount` plus the fixed part.",
            "example": "1.75"
          },
          "asset": {
            "type": "string",
            "description": "The asset the fee is paid in.",
            "example": "XLM"
          },
          "wallet": {
            "type": "string",
            "description": "Where the fee is paid.",
            "example": "GBDHAQXQQ75WVBUZ2IX3O7ME7JOKJUOUPUXRNDCORUJODWQCTVUEQ62R"
          },
          "paidBy": {
            "type": "string",
            "enum": [
              "recipient",
              "payer"
            ],
            "description": "`recipient`: deducted from the amount. `payer`: added on top of it.",
            "example": "recipient"
          },
          "amountB": {
            "type": "string",
            "description": "The fee charged on asset B, in asset B.",
            "example": "0.05"
          },
          "assetB": {
            "type": "string",
            "description": "Asset B (`native` for XLM).",
            "example": "USDC"
          }
        },
        "description": "The merchant fee a liquidity operation charged: `bps` of each asset, with `amount` and `asset` for asset A and `amountB` and `assetB` for asset B.",
        "required": [
          "bps",
          "fixed",
          "amount",
          "asset",
          "wallet",
          "paidBy",
          "amountB",
          "assetB"
        ]
      },
      "LiquidityOperationEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "The operation's id, used by the read and submit routes."
          },
          "kind": {
            "type": "string",
            "enum": [
              "DEPOSIT",
              "WITHDRAW"
            ],
            "example": "DEPOSIT",
            "description": "`DEPOSIT` adds both assets to the pool; `WITHDRAW` burns pool shares for both reserves."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "PENDING (built, unsigned), SUBMITTED (a signed transaction was sent to the network), SUCCEEDED (confirmed on the ledger), FAILED (rejected on the network) or EXPIRED (time bounds elapsed before submission)."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The Stellar network the operation targets, which follows the API key: `public` (mainnet) or `testnet`."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The Stellar account that funds and signs the operation: the transaction source."
          },
          "poolId": {
            "type": "string",
            "example": "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7",
            "description": "Stellar liquidity pool id (64-character lowercase hex)."
          },
          "assetA": {
            "type": "string",
            "example": "native",
            "description": "Asset A's code (`native` for XLM). The pair is stored in the protocol's canonical order (A < B)."
          },
          "assetAIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Asset A's issuer account; null for native XLM."
          },
          "assetB": {
            "type": "string",
            "example": "USDC",
            "description": "Asset B's code (`native` for XLM)."
          },
          "assetBIssuer": {
            "type": "object",
            "nullable": true,
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6",
            "description": "Asset B's issuer account; null for native XLM."
          },
          "amountA": {
            "type": "string",
            "example": "1000",
            "description": "DEPOSIT: maxAmountA cap. WITHDRAW: slippage-protected minimum of asset A."
          },
          "amountB": {
            "type": "string",
            "example": "100",
            "description": "DEPOSIT: maxAmountB cap. WITHDRAW: slippage-protected minimum of asset B."
          },
          "shares": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Pool shares burned (WITHDRAW only)."
          },
          "minPrice": {
            "type": "object",
            "nullable": true,
            "example": "9.95",
            "description": "A DEPOSIT's lower price bound (its `liquidityPoolDeposit` minPrice), in asset A per unit of asset B, as a decimal string of up to 7 places: the pool price when the operation was built (reserve A / reserve B, or `amountA` / `amountB` for a pool with no reserves yet) less `slippageBps`, rounded down. The deposit fails on-chain at a price below it. Null on a WITHDRAW."
          },
          "maxPrice": {
            "type": "object",
            "nullable": true,
            "example": "10.05",
            "description": "A DEPOSIT's upper price bound (its `liquidityPoolDeposit` maxPrice), in the same units as `minPrice`: the same pool price plus `slippageBps`, rounded up. The deposit fails on-chain at a price above it. Null on a WITHDRAW."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "The slippage tolerance the operation was built with, in basis points (50 = 0.5%)."
          },
          "memo": {
            "type": "string",
            "nullable": true,
            "example": "4242",
            "description": "The caller's MEMO_ID (uint64 as a string), null when none was supplied. A commission MEMO_TEXT is reported in `commissionMemo`, never here. Operations created before this field existed report null even when their envelope carries a MEMO_ID; the `xdr` is authoritative for those."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": "lp-deposit-2026-08-23-001",
            "description": "Client idempotency key when supplied via Idempotency-Key / body (null otherwise)."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "Plan commission in basis points (50 = 0.5%), applied to both assets."
          },
          "feeAmountA": {
            "type": "string",
            "example": "5",
            "description": "Commission taken from asset A (deducted from the deposit / the withdrawn minimum). \"0\" when no commission applies."
          },
          "feeAmountB": {
            "type": "string",
            "example": "0.5",
            "description": "Commission taken from asset B. \"0\" when none."
          },
          "feeWallet": {
            "type": "object",
            "nullable": true,
            "example": "GBFEE...WALLET",
            "description": "Commission collector account (null when the fee is disabled)."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee the request named: `bps` of each asset, `amount` in asset A and `amountB` in asset B, paid to `wallet` in this transaction; null without one.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/LiquidityMerchantFeeEntity"
              }
            ]
          },
          "commissionMemo": {
            "type": "object",
            "nullable": true,
            "example": "Cosmos Liquidity Commission",
            "description": "On-chain MEMO_TEXT label stamped when a commission is collected and no caller memo was supplied (null when no commission applies)."
          },
          "xdr": {
            "type": "string",
            "description": "Unsigned transaction envelope (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "A SEP-7 `tx` URI carrying `xdr`, for a wallet to sign."
          },
          "txHash": {
            "type": "string",
            "description": "Deterministic transaction hash (verified on submit).",
            "example": "3389e9f0...64hex"
          },
          "qr": {
            "type": "string",
            "example": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA…",
            "description": "A QR code of `uri`, as a PNG data URL."
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "example": "2026-07-04T12:39:56.000Z",
            "description": "When the transaction's validity window closes (ISO 8601 date-time); after it the transaction can no longer settle."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-07-04T12:34:56.000Z",
            "description": "When the operation was built (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-07-04T12:34:56.000Z",
            "description": "When the operation was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A liquidity pool deposit or withdrawal built by this service: the stored operation with its unsigned transaction, SEP-7 link and QR.",
        "required": [
          "id",
          "kind",
          "status",
          "network",
          "source",
          "poolId",
          "assetA",
          "assetAIssuer",
          "assetB",
          "assetBIssuer",
          "amountA",
          "amountB",
          "shares",
          "minPrice",
          "maxPrice",
          "slippageBps",
          "feeBps",
          "feeAmountA",
          "feeAmountB",
          "feeWallet",
          "merchantFee",
          "commissionMemo",
          "xdr",
          "uri",
          "txHash",
          "qr",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "WithdrawLiquidityDto": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "description": "Account holding the pool shares (and signing): the tx source.",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ"
          },
          "poolId": {
            "type": "string",
            "description": "Stellar liquidity pool id (64-char hex).",
            "example": "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7"
          },
          "shares": {
            "type": "string",
            "description": "Amount of pool shares to burn (decimal, ≤ 7 places).",
            "example": "50"
          },
          "slippageBps": {
            "type": "number",
            "description": "Slippage tolerance in basis points (50 = 0.5%) used to derive the on-chain minimum received per reserve. Defaults to the service setting.",
            "example": 50
          },
          "memo": {
            "type": "string",
            "description": "Optional MEMO_ID (numeric uint64) echoed on-chain for reconciliation.",
            "example": "123456789"
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Optional idempotency key. Prefer the `Idempotency-Key` request header; when both are set, the header wins. A retry with the same key and the same request returns the existing operation instead of building another transaction; the same key with a different request is 409 `idempotency_conflict`.",
            "example": "lp-withdraw-2026-08-23-001"
          },
          "merchantFee": {
            "description": "Your own fee on this withdrawal: `bps` of EACH asset it moves, paid to `wallet` (a Stellar account that can receive both assets) by one payment per asset in the same transaction, beside the plan commission. `fixed` is refused here: the operation moves two assets. The fee comes out of what the withdrawal pays, on its guaranteed minimums, whichever `paidBy` names: the account is payer and receiver.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "A liquidity pool withdrawal request: burn `shares` pool shares for the proportional amounts of both reserves, protected by slippage-derived on-chain minimums.",
        "required": [
          "source",
          "poolId",
          "shares"
        ]
      },
      "LiquidityPoolReserve": {
        "type": "object",
        "properties": {
          "asset": {
            "type": "string",
            "example": "native",
            "description": "Asset code, or \"native\"."
          },
          "issuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "The asset's issuer account; null for native XLM."
          },
          "amount": {
            "type": "string",
            "example": "82944.5873463",
            "description": "Amount of the asset, as a decimal string in the asset's units (up to 7 decimal places)."
          }
        },
        "description": "One side of a liquidity pool: an asset and how much of it the pool holds, or a holder can redeem.",
        "required": [
          "asset",
          "issuer",
          "amount"
        ]
      },
      "LiquidityPositionEntity": {
        "type": "object",
        "properties": {
          "poolId": {
            "type": "string",
            "example": "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7",
            "description": "Stellar liquidity pool id (64-character lowercase hex)."
          },
          "shares": {
            "type": "string",
            "example": "50.25",
            "description": "Pool shares held."
          },
          "totalShares": {
            "type": "string",
            "example": "4462.7227546",
            "description": "Total pool shares outstanding, as a decimal string (up to 7 decimal places)."
          },
          "shareOfPoolBps": {
            "type": "number",
            "example": 112,
            "description": "Share of the pool in basis points (112 = 1.12%)."
          },
          "reserves": {
            "description": "The pool's two reserves, in canonical order.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiquidityPoolReserve"
            }
          },
          "redeemable": {
            "description": "What the shares redeem to at current reserves (pre-slippage).",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiquidityPoolReserve"
            }
          }
        },
        "description": "An account's stake in one liquidity pool, with what its shares redeem at the current reserves.",
        "required": [
          "poolId",
          "shares",
          "totalShares",
          "shareOfPoolBps",
          "reserves",
          "redeemable"
        ]
      },
      "LiquidityPositionListEntity": {
        "type": "object",
        "properties": {
          "account": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The Stellar account whose positions are listed."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The Stellar network read, which follows the API key: `public` (mainnet) or `testnet`."
          },
          "data": {
            "description": "One position per pool the account holds shares in.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiquidityPositionEntity"
            }
          }
        },
        "description": "An account's liquidity pool share positions, read from Horizon on the API key's network. Nothing is persisted.",
        "required": [
          "account",
          "network",
          "data"
        ]
      },
      "LiquidityOperationListItemEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "The operation's id, used by the read and submit routes."
          },
          "kind": {
            "type": "string",
            "enum": [
              "DEPOSIT",
              "WITHDRAW"
            ],
            "example": "DEPOSIT",
            "description": "`DEPOSIT` adds both assets to the pool; `WITHDRAW` burns pool shares for both reserves."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "PENDING (built, unsigned), SUBMITTED (a signed transaction was sent to the network), SUCCEEDED (confirmed on the ledger), FAILED (rejected on the network) or EXPIRED (time bounds elapsed before submission)."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The Stellar network the operation targets, which follows the API key: `public` (mainnet) or `testnet`."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The Stellar account that funds and signs the operation: the transaction source."
          },
          "poolId": {
            "type": "string",
            "example": "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7",
            "description": "Stellar liquidity pool id (64-character lowercase hex)."
          },
          "assetA": {
            "type": "string",
            "example": "native",
            "description": "Asset A's code (`native` for XLM). The pair is stored in the protocol's canonical order (A < B)."
          },
          "assetAIssuer": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Asset A's issuer account; null for native XLM."
          },
          "assetB": {
            "type": "string",
            "example": "USDC",
            "description": "Asset B's code (`native` for XLM)."
          },
          "assetBIssuer": {
            "type": "object",
            "nullable": true,
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTR6F3DSZL5A3W4G4M4N4A5U4QY3T6",
            "description": "Asset B's issuer account; null for native XLM."
          },
          "amountA": {
            "type": "string",
            "example": "1000",
            "description": "DEPOSIT: maxAmountA cap. WITHDRAW: slippage-protected minimum of asset A."
          },
          "amountB": {
            "type": "string",
            "example": "100",
            "description": "DEPOSIT: maxAmountB cap. WITHDRAW: slippage-protected minimum of asset B."
          },
          "shares": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Pool shares burned (WITHDRAW only)."
          },
          "minPrice": {
            "type": "object",
            "nullable": true,
            "example": "9.95",
            "description": "A DEPOSIT's lower price bound (its `liquidityPoolDeposit` minPrice), in asset A per unit of asset B, as a decimal string of up to 7 places: the pool price when the operation was built (reserve A / reserve B, or `amountA` / `amountB` for a pool with no reserves yet) less `slippageBps`, rounded down. The deposit fails on-chain at a price below it. Null on a WITHDRAW."
          },
          "maxPrice": {
            "type": "object",
            "nullable": true,
            "example": "10.05",
            "description": "A DEPOSIT's upper price bound (its `liquidityPoolDeposit` maxPrice), in the same units as `minPrice`: the same pool price plus `slippageBps`, rounded up. The deposit fails on-chain at a price above it. Null on a WITHDRAW."
          },
          "slippageBps": {
            "type": "number",
            "example": 50,
            "description": "The slippage tolerance the operation was built with, in basis points (50 = 0.5%)."
          },
          "memo": {
            "type": "string",
            "nullable": true,
            "example": "4242",
            "description": "The caller's MEMO_ID (uint64 as a string), null when none was supplied. A commission MEMO_TEXT is reported in `commissionMemo`, never here. Operations created before this field existed report null even when their envelope carries a MEMO_ID; the `xdr` is authoritative for those."
          },
          "idempotencyKey": {
            "type": "object",
            "nullable": true,
            "example": "lp-deposit-2026-08-23-001",
            "description": "Client idempotency key when supplied via Idempotency-Key / body (null otherwise)."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "Plan commission in basis points (50 = 0.5%), applied to both assets."
          },
          "feeAmountA": {
            "type": "string",
            "example": "5",
            "description": "Commission taken from asset A (deducted from the deposit / the withdrawn minimum). \"0\" when no commission applies."
          },
          "feeAmountB": {
            "type": "string",
            "example": "0.5",
            "description": "Commission taken from asset B. \"0\" when none."
          },
          "feeWallet": {
            "type": "object",
            "nullable": true,
            "example": "GBFEE...WALLET",
            "description": "Commission collector account (null when the fee is disabled)."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee the request named: `bps` of each asset, `amount` in asset A and `amountB` in asset B, paid to `wallet` in this transaction; null without one.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/LiquidityMerchantFeeEntity"
              }
            ]
          },
          "xdr": {
            "type": "string",
            "description": "Unsigned transaction envelope (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "A SEP-7 `tx` URI carrying `xdr`, for a wallet to sign."
          },
          "txHash": {
            "type": "string",
            "description": "Deterministic transaction hash (verified on submit).",
            "example": "3389e9f0...64hex"
          },
          "expiresAt": {
            "type": "object",
            "nullable": true,
            "example": "2026-07-04T12:39:56.000Z",
            "description": "When the transaction's validity window closes (ISO 8601 date-time); after it the transaction can no longer settle."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-07-04T12:34:56.000Z",
            "description": "When the operation was built (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-07-04T12:34:56.000Z",
            "description": "When the operation was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A liquidity pool operation as the list returns it: every field but `qr` and `commissionMemo`, which only the single read derives.",
        "required": [
          "id",
          "kind",
          "status",
          "network",
          "source",
          "poolId",
          "assetA",
          "assetAIssuer",
          "assetB",
          "assetBIssuer",
          "amountA",
          "amountB",
          "shares",
          "minPrice",
          "maxPrice",
          "slippageBps",
          "feeBps",
          "feeAmountA",
          "feeAmountB",
          "feeWallet",
          "merchantFee",
          "xdr",
          "uri",
          "txHash",
          "expiresAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "LiquidityOperationListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The operations on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiquidityOperationListItemEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "How many operations match the filters, across all pages."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "The page size applied."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "How many matching operations were skipped before this page."
          }
        },
        "description": "A page of the consumer's liquidity pool operations on the API key's network, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "SubmitLiquidityDto": {
        "type": "object",
        "properties": {
          "signedXdr": {
            "type": "string",
            "description": "The signed transaction envelope (base64 XDR).",
            "example": "AAAAAgAAAABx…(signed base64 XDR)…AAAAAAAAAAA="
          }
        },
        "description": "The signed transaction of a liquidity pool operation, to relay to the network. It must be the transaction the service built (its hash is checked) and carry a signature.",
        "required": [
          "signedXdr"
        ]
      },
      "LiquiditySubmitResultEntity": {
        "type": "object",
        "properties": {
          "submitted": {
            "type": "boolean",
            "example": true,
            "description": "True when the transaction was confirmed on the ledger (status SUCCEEDED); false when this broadcast was rejected (see `reason`)."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "SUCCEEDED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "SUCCEEDED",
            "description": "The operation's status after this submission."
          },
          "txHash": {
            "type": "string",
            "nullable": true,
            "example": "3389e9f0...64hex",
            "description": "The on-chain transaction hash once submitted."
          },
          "reason": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Why submission failed, when `submitted` is false. With `status` FAILED the ledger confirms the failure; with `status` SUBMITTED the network refused this broadcast but the transaction may still be on the ledger, and its outcome arrives as a terminal webhook."
          },
          "resultCodes": {
            "nullable": true,
            "example": [
              "op_bad_price"
            ],
            "description": "Horizon transaction/operation result codes on a rejection.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "operation": {
            "description": "The operation after this submission.",
            "allOf": [
              {
                "$ref": "#/components/schemas/LiquidityOperationEntity"
              }
            ]
          }
        },
        "description": "The result of relaying a signed liquidity pool transaction, with the operation as it stands afterwards.",
        "required": [
          "submitted",
          "status",
          "operation"
        ]
      },
      "LiquidityPoolEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "dd7b1ab831c273310ddbec6f97870aa83c2fbd78ce22aded37ecbf4f3380fac7",
            "description": "Stellar liquidity pool id (64-character lowercase hex)."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "The Stellar network the pool was read from, which follows the API key: `public` (mainnet) or `testnet`."
          },
          "feeBp": {
            "type": "number",
            "example": 30,
            "description": "Pool fee in basis points (0.3%)."
          },
          "totalTrustlines": {
            "type": "string",
            "example": "123",
            "description": "Accounts holding pool shares."
          },
          "totalShares": {
            "type": "string",
            "example": "4462.7227546",
            "description": "Total pool shares outstanding, as a decimal string (up to 7 decimal places)."
          },
          "reserves": {
            "description": "Both reserves, canonical order.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiquidityPoolReserve"
            }
          }
        },
        "description": "An on-chain Stellar liquidity pool, read from Horizon on the API key's network. Nothing is persisted.",
        "required": [
          "id",
          "network",
          "feeBp",
          "totalTrustlines",
          "totalShares",
          "reserves"
        ]
      },
      "LiquidityPoolListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The pools on this page, in Horizon's descending order.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/LiquidityPoolEntity"
            }
          },
          "cursor": {
            "type": "object",
            "nullable": true,
            "example": "113725249324879873",
            "description": "Horizon paging cursor for the next page (null when done)."
          }
        },
        "description": "A page of on-chain liquidity pools from Horizon, with the cursor for the next page.",
        "required": [
          "data",
          "cursor"
        ]
      },
      "AssetIssuerFlagsEntity": {
        "type": "object",
        "properties": {
          "authRevocable": {
            "type": "boolean",
            "example": true,
            "description": "The issuer may freeze this trustline."
          },
          "clawback": {
            "type": "boolean",
            "example": false,
            "description": "The issuer may claw the balance back out of the holder."
          }
        },
        "description": "Issuer powers over an asset that a holder cannot undo once the trustline exists.",
        "required": [
          "authRevocable",
          "clawback"
        ]
      },
      "AssetEntity": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "USDT0",
            "description": "Stellar asset code (1 to 12 alphanumeric characters); `XLM` for the native asset."
          },
          "issuer": {
            "type": "object",
            "nullable": true,
            "example": "GATISXX6BZ6NC7IKQBY37CJD4SOZL3CYZJWXEDG6JVIY4WBS6KXJHN6Q",
            "description": "Issuing account, or null for native XLM."
          },
          "name": {
            "type": "string",
            "example": "USDT0",
            "description": "Display name of the asset (e.g. `USD Coin`)."
          },
          "issuerName": {
            "type": "string",
            "example": "Tether",
            "description": "Who issues it, for display next to the code."
          },
          "issuerDomain": {
            "type": "string",
            "example": "circle.com",
            "description": "The issuer's on-chain home_domain, or empty when it publishes none, which is the case for USDT0 and every testnet issuer. Never a domain attributed by a third party: rendered next to a token, that reads as the issuer's own claim."
          },
          "verified": {
            "type": "boolean",
            "example": true,
            "description": "Whether the issuing account was checked against the named organization. A claim about identity, not about quality: render unverified rows differently rather than hiding them."
          },
          "contract": {
            "type": "object",
            "nullable": true,
            "example": "CBSJZEIO5C7KC2SF3MKSNXXJSW5G3VTNBX4ATMKUI3B2MR4JKM4R26YF",
            "description": "Stellar Asset Contract id, when wrapped for Soroban."
          },
          "flags": {
            "description": "Issuer powers over the holder's trustline.",
            "allOf": [
              {
                "$ref": "#/components/schemas/AssetIssuerFlagsEntity"
              }
            ]
          }
        },
        "description": "One catalogued Stellar asset with its issuer's identity. `code` and `issuer` together identify it; neither alone does.",
        "required": [
          "code",
          "issuer",
          "name",
          "issuerName",
          "issuerDomain",
          "verified",
          "contract",
          "flags"
        ]
      },
      "AssetListEntity": {
        "type": "object",
        "properties": {
          "network": {
            "type": "string",
            "example": "public",
            "enum": [
              "public",
              "testnet"
            ],
            "description": "The Stellar network listed: `public` (mainnet) or `testnet`."
          },
          "version": {
            "type": "number",
            "example": 1,
            "description": "Monotonic registry version. A client holding a bundled copy compares this against its own and keeps whichever is newer."
          },
          "data": {
            "description": "The catalogued assets of that network.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetEntity"
            }
          }
        },
        "description": "The asset catalog of one Stellar network, with its registry version.",
        "required": [
          "network",
          "version",
          "data"
        ]
      },
      "PublicKeyEntity": {
        "type": "object",
        "properties": {
          "env": {
            "type": "string",
            "enum": [
              "dev",
              "prod"
            ],
            "example": "dev",
            "description": "`dev` for the testnet key, `prod` for the mainnet one."
          },
          "apiKey": {
            "type": "string",
            "example": "dv_4f1c9a7e0b2d6c8e3a5f7b9d1e3c5a7f9b1d3e5c7a9f1b3d5e7c9a1f3b5d7e9c",
            "description": "The shared key every wallet without an account of its own presents. Not a secret: it ships inside an open-source wallet, and what it may reach is confined server-side to the routes marked for it."
          }
        },
        "description": "The shared public API key of one environment, for wallets without an account of their own.",
        "required": [
          "env",
          "apiKey"
        ]
      },
      "CreateWebhookEndpointDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "HTTPS URL that will receive POSTed event notifications.",
            "example": "https://integrator.example.com/webhooks/cosmos"
          },
          "description": {
            "type": "string",
            "example": "Production payment events",
            "description": "Free-text label for the endpoint (at most 255 characters)."
          },
          "eventTypes": {
            "type": "array",
            "description": "Event types to subscribe to. Omit/empty to receive all events.",
            "items": {
              "type": "string",
              "enum": [
                "PAYMENT_INTENT_CREATED",
                "PAYMENT_INTENT_UPDATED",
                "PAYMENT_INTENT_SUCCEEDED",
                "PAYMENT_INTENT_FAILED",
                "PAYMENT_INTENT_CANCELLED",
                "PAYMENT_INTENT_DELETED",
                "RECEIVER_UPDATED",
                "PAYIN_CREATED",
                "PAYIN_UPDATED",
                "PAYIN_COMPLETED",
                "PAYOUT_CREATED",
                "PAYOUT_UPDATED",
                "PAYOUT_COMPLETED",
                "SWAP_CREATED",
                "SWAP_SUBMITTED",
                "SWAP_SUCCEEDED",
                "SWAP_FAILED",
                "LIQUIDITY_CREATED",
                "LIQUIDITY_SUBMITTED",
                "LIQUIDITY_SUCCEEDED",
                "LIQUIDITY_FAILED",
                "SWAP_EXPIRED",
                "LIQUIDITY_EXPIRED",
                "CROSS_CHAIN_SWAP_CREATED",
                "CROSS_CHAIN_SWAP_UPDATED",
                "CROSS_CHAIN_SWAP_SUCCEEDED",
                "CROSS_CHAIN_SWAP_REFUNDED",
                "CROSS_CHAIN_SWAP_FAILED",
                "CROSS_CHAIN_SWAP_EXPIRED",
                "ZK_PAYMENT_SUCCEEDED",
                "PROTECTED_PAYMENT_CREATED",
                "PROTECTED_PAYMENT_FUNDED",
                "PROTECTED_PAYMENT_SHIPPED",
                "PROTECTED_PAYMENT_APPROVED",
                "PROTECTED_PAYMENT_RELEASED",
                "PROTECTED_PAYMENT_DISPUTED",
                "PROTECTED_PAYMENT_RESOLVED",
                "PROTECTED_PAYMENT_DEADLINE_PASSED",
                "PROTECTED_PAYMENT_EXPIRED",
                "PROTECTED_PAYMENT_CANCELLED"
              ]
            }
          }
        },
        "description": "A webhook endpoint to register: an https URL that receives signed event notifications.",
        "required": [
          "url"
        ]
      },
      "WebhookEndpointWithSecretEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "we_9z8a1b0000abcd1234efgh",
            "description": "Webhook endpoint id."
          },
          "url": {
            "type": "string",
            "example": "https://integrator.example.com/webhooks/cosmos",
            "description": "The https URL deliveries are POSTed to."
          },
          "description": {
            "type": "object",
            "nullable": true,
            "example": "Production payment events",
            "description": "Free-text label for the endpoint; null when none was given."
          },
          "enabled": {
            "type": "boolean",
            "example": true,
            "description": "Whether deliveries are sent to this endpoint."
          },
          "destinationBlocked": {
            "type": "boolean",
            "example": false,
            "description": "True when the URL failed public-destination checks (SSRF policy). Deliveries are skipped until the URL is updated to a safe https endpoint."
          },
          "eventTypes": {
            "type": "array",
            "example": [
              "PAYMENT_INTENT_SUCCEEDED"
            ],
            "description": "Subscribed events; empty means all.",
            "items": {
              "type": "string",
              "enum": [
                "PAYMENT_INTENT_CREATED",
                "PAYMENT_INTENT_UPDATED",
                "PAYMENT_INTENT_SUCCEEDED",
                "PAYMENT_INTENT_FAILED",
                "PAYMENT_INTENT_CANCELLED",
                "PAYMENT_INTENT_DELETED",
                "RECEIVER_UPDATED",
                "PAYIN_CREATED",
                "PAYIN_UPDATED",
                "PAYIN_COMPLETED",
                "PAYOUT_CREATED",
                "PAYOUT_UPDATED",
                "PAYOUT_COMPLETED",
                "SWAP_CREATED",
                "SWAP_SUBMITTED",
                "SWAP_SUCCEEDED",
                "SWAP_FAILED",
                "LIQUIDITY_CREATED",
                "LIQUIDITY_SUBMITTED",
                "LIQUIDITY_SUCCEEDED",
                "LIQUIDITY_FAILED",
                "SWAP_EXPIRED",
                "LIQUIDITY_EXPIRED",
                "CROSS_CHAIN_SWAP_CREATED",
                "CROSS_CHAIN_SWAP_UPDATED",
                "CROSS_CHAIN_SWAP_SUCCEEDED",
                "CROSS_CHAIN_SWAP_REFUNDED",
                "CROSS_CHAIN_SWAP_FAILED",
                "CROSS_CHAIN_SWAP_EXPIRED",
                "ZK_PAYMENT_SUCCEEDED",
                "PROTECTED_PAYMENT_CREATED",
                "PROTECTED_PAYMENT_FUNDED",
                "PROTECTED_PAYMENT_SHIPPED",
                "PROTECTED_PAYMENT_APPROVED",
                "PROTECTED_PAYMENT_RELEASED",
                "PROTECTED_PAYMENT_DISPUTED",
                "PROTECTED_PAYMENT_RESOLVED",
                "PROTECTED_PAYMENT_DEADLINE_PASSED",
                "PROTECTED_PAYMENT_EXPIRED",
                "PROTECTED_PAYMENT_CANCELLED"
              ]
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the endpoint was registered (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the endpoint last changed (ISO 8601)."
          },
          "secret": {
            "type": "string",
            "description": "HMAC signing secret, shown once. Store it securely.",
            "example": "whsec_3f9a1c…"
          }
        },
        "description": "A webhook endpoint with its signing secret, returned only when it is created and when its secret is rotated.",
        "required": [
          "id",
          "url",
          "description",
          "enabled",
          "destinationBlocked",
          "eventTypes",
          "createdAt",
          "updatedAt",
          "secret"
        ]
      },
      "WebhookEndpointEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "we_9z8a1b0000abcd1234efgh",
            "description": "Webhook endpoint id."
          },
          "url": {
            "type": "string",
            "example": "https://integrator.example.com/webhooks/cosmos",
            "description": "The https URL deliveries are POSTed to."
          },
          "description": {
            "type": "object",
            "nullable": true,
            "example": "Production payment events",
            "description": "Free-text label for the endpoint; null when none was given."
          },
          "enabled": {
            "type": "boolean",
            "example": true,
            "description": "Whether deliveries are sent to this endpoint."
          },
          "destinationBlocked": {
            "type": "boolean",
            "example": false,
            "description": "True when the URL failed public-destination checks (SSRF policy). Deliveries are skipped until the URL is updated to a safe https endpoint."
          },
          "eventTypes": {
            "type": "array",
            "example": [
              "PAYMENT_INTENT_SUCCEEDED"
            ],
            "description": "Subscribed events; empty means all.",
            "items": {
              "type": "string",
              "enum": [
                "PAYMENT_INTENT_CREATED",
                "PAYMENT_INTENT_UPDATED",
                "PAYMENT_INTENT_SUCCEEDED",
                "PAYMENT_INTENT_FAILED",
                "PAYMENT_INTENT_CANCELLED",
                "PAYMENT_INTENT_DELETED",
                "RECEIVER_UPDATED",
                "PAYIN_CREATED",
                "PAYIN_UPDATED",
                "PAYIN_COMPLETED",
                "PAYOUT_CREATED",
                "PAYOUT_UPDATED",
                "PAYOUT_COMPLETED",
                "SWAP_CREATED",
                "SWAP_SUBMITTED",
                "SWAP_SUCCEEDED",
                "SWAP_FAILED",
                "LIQUIDITY_CREATED",
                "LIQUIDITY_SUBMITTED",
                "LIQUIDITY_SUCCEEDED",
                "LIQUIDITY_FAILED",
                "SWAP_EXPIRED",
                "LIQUIDITY_EXPIRED",
                "CROSS_CHAIN_SWAP_CREATED",
                "CROSS_CHAIN_SWAP_UPDATED",
                "CROSS_CHAIN_SWAP_SUCCEEDED",
                "CROSS_CHAIN_SWAP_REFUNDED",
                "CROSS_CHAIN_SWAP_FAILED",
                "CROSS_CHAIN_SWAP_EXPIRED",
                "ZK_PAYMENT_SUCCEEDED",
                "PROTECTED_PAYMENT_CREATED",
                "PROTECTED_PAYMENT_FUNDED",
                "PROTECTED_PAYMENT_SHIPPED",
                "PROTECTED_PAYMENT_APPROVED",
                "PROTECTED_PAYMENT_RELEASED",
                "PROTECTED_PAYMENT_DISPUTED",
                "PROTECTED_PAYMENT_RESOLVED",
                "PROTECTED_PAYMENT_DEADLINE_PASSED",
                "PROTECTED_PAYMENT_EXPIRED",
                "PROTECTED_PAYMENT_CANCELLED"
              ]
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the endpoint was registered (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the endpoint last changed (ISO 8601)."
          }
        },
        "description": "A webhook endpoint of the consumer, without its signing secret.",
        "required": [
          "id",
          "url",
          "description",
          "enabled",
          "destinationBlocked",
          "eventTypes",
          "createdAt",
          "updatedAt"
        ]
      },
      "WebhookEndpointListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The endpoints on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookEndpointEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "Number of endpoints, across every page."
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "Page size applied (1 to 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Number of endpoints skipped before this page."
          }
        },
        "description": "One page of the consumer's webhook endpoints, newest first, without signing secrets.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "UpdateWebhookEndpointDto": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "example": "https://integrator.example.com/webhooks/cosmos",
            "description": "New https URL for deliveries, checked as on create."
          },
          "description": {
            "type": "string",
            "description": "Free-text label for the endpoint (at most 255 characters)."
          },
          "enabled": {
            "type": "boolean",
            "description": "Pause/resume deliveries to this endpoint."
          },
          "eventTypes": {
            "type": "array",
            "description": "Event types to subscribe to; replaces the current filter. An empty list receives every event type.",
            "items": {
              "type": "string",
              "enum": [
                "PAYMENT_INTENT_CREATED",
                "PAYMENT_INTENT_UPDATED",
                "PAYMENT_INTENT_SUCCEEDED",
                "PAYMENT_INTENT_FAILED",
                "PAYMENT_INTENT_CANCELLED",
                "PAYMENT_INTENT_DELETED",
                "RECEIVER_UPDATED",
                "PAYIN_CREATED",
                "PAYIN_UPDATED",
                "PAYIN_COMPLETED",
                "PAYOUT_CREATED",
                "PAYOUT_UPDATED",
                "PAYOUT_COMPLETED",
                "SWAP_CREATED",
                "SWAP_SUBMITTED",
                "SWAP_SUCCEEDED",
                "SWAP_FAILED",
                "LIQUIDITY_CREATED",
                "LIQUIDITY_SUBMITTED",
                "LIQUIDITY_SUCCEEDED",
                "LIQUIDITY_FAILED",
                "SWAP_EXPIRED",
                "LIQUIDITY_EXPIRED",
                "CROSS_CHAIN_SWAP_CREATED",
                "CROSS_CHAIN_SWAP_UPDATED",
                "CROSS_CHAIN_SWAP_SUCCEEDED",
                "CROSS_CHAIN_SWAP_REFUNDED",
                "CROSS_CHAIN_SWAP_FAILED",
                "CROSS_CHAIN_SWAP_EXPIRED",
                "ZK_PAYMENT_SUCCEEDED",
                "PROTECTED_PAYMENT_CREATED",
                "PROTECTED_PAYMENT_FUNDED",
                "PROTECTED_PAYMENT_SHIPPED",
                "PROTECTED_PAYMENT_APPROVED",
                "PROTECTED_PAYMENT_RELEASED",
                "PROTECTED_PAYMENT_DISPUTED",
                "PROTECTED_PAYMENT_RESOLVED",
                "PROTECTED_PAYMENT_DEADLINE_PASSED",
                "PROTECTED_PAYMENT_EXPIRED",
                "PROTECTED_PAYMENT_CANCELLED"
              ]
            }
          }
        },
        "description": "Changes to a webhook endpoint; only the fields sent change."
      },
      "WebhookDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "we_9z8a1b0000abcd1234efgh",
            "description": "Id of the deleted endpoint."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirmation that a webhook endpoint and its delivery history were deleted.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "WebhookPingEntity": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "example": true,
            "description": "True when the endpoint answered with a 2xx status."
          },
          "responseStatus": {
            "type": "object",
            "nullable": true,
            "example": 200,
            "description": "HTTP status the endpoint answered; null when the request got no response."
          },
          "error": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Why the request failed when it got no response; null otherwise."
          }
        },
        "description": "Result of sending one signed test `ping` event to a webhook endpoint.",
        "required": [
          "ok",
          "responseStatus",
          "error"
        ]
      },
      "WebhookDeliveryEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "wd_9z8a1b0000abcd1234efgh",
            "description": "Delivery id."
          },
          "endpointId": {
            "type": "string",
            "example": "we_9z8a1b0000abcd1234efgh",
            "description": "Id of the endpoint the event was sent to."
          },
          "eventType": {
            "type": "string",
            "enum": [
              "PAYMENT_INTENT_CREATED",
              "PAYMENT_INTENT_UPDATED",
              "PAYMENT_INTENT_SUCCEEDED",
              "PAYMENT_INTENT_FAILED",
              "PAYMENT_INTENT_CANCELLED",
              "PAYMENT_INTENT_DELETED",
              "RECEIVER_UPDATED",
              "PAYIN_CREATED",
              "PAYIN_UPDATED",
              "PAYIN_COMPLETED",
              "PAYOUT_CREATED",
              "PAYOUT_UPDATED",
              "PAYOUT_COMPLETED",
              "SWAP_CREATED",
              "SWAP_SUBMITTED",
              "SWAP_SUCCEEDED",
              "SWAP_FAILED",
              "LIQUIDITY_CREATED",
              "LIQUIDITY_SUBMITTED",
              "LIQUIDITY_SUCCEEDED",
              "LIQUIDITY_FAILED",
              "SWAP_EXPIRED",
              "LIQUIDITY_EXPIRED",
              "CROSS_CHAIN_SWAP_CREATED",
              "CROSS_CHAIN_SWAP_UPDATED",
              "CROSS_CHAIN_SWAP_SUCCEEDED",
              "CROSS_CHAIN_SWAP_REFUNDED",
              "CROSS_CHAIN_SWAP_FAILED",
              "CROSS_CHAIN_SWAP_EXPIRED",
              "ZK_PAYMENT_SUCCEEDED",
              "PROTECTED_PAYMENT_CREATED",
              "PROTECTED_PAYMENT_FUNDED",
              "PROTECTED_PAYMENT_SHIPPED",
              "PROTECTED_PAYMENT_APPROVED",
              "PROTECTED_PAYMENT_RELEASED",
              "PROTECTED_PAYMENT_DISPUTED",
              "PROTECTED_PAYMENT_RESOLVED",
              "PROTECTED_PAYMENT_DEADLINE_PASSED",
              "PROTECTED_PAYMENT_EXPIRED",
              "PROTECTED_PAYMENT_CANCELLED"
            ],
            "example": "PAYMENT_INTENT_SUCCEEDED",
            "description": "Type of the event delivered."
          },
          "eventId": {
            "type": "string",
            "example": "evt_2c3d4e5f-aaaa-bbbb-cccc-1234567890ab",
            "description": "Stable event id sent to the receiver (`x-cosmos-event-id`), for idempotency."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUCCEEDED",
              "FAILED",
              "RETRYING"
            ],
            "example": "SUCCEEDED",
            "description": "Delivery outcome: `PENDING` while it is being sent, `SUCCEEDED` once the endpoint answered 2xx, `FAILED` when no attempt did."
          },
          "attempts": {
            "type": "number",
            "example": 1,
            "description": "Number of POST attempts made so far."
          },
          "responseStatus": {
            "type": "object",
            "nullable": true,
            "example": 200,
            "description": "HTTP status of the last attempt; null when it got no response."
          },
          "error": {
            "type": "object",
            "nullable": true,
            "example": null,
            "description": "Why the last attempt failed (e.g. `Non-2xx response: 500`); null on success."
          },
          "lastAttemptAt": {
            "type": "object",
            "nullable": true,
            "example": "2026-06-21T12:34:57.000Z",
            "description": "When the last attempt was made (ISO 8601); null before the first."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:56.000Z",
            "description": "When the delivery was created (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-21T12:34:57.000Z",
            "description": "When the delivery last changed (ISO 8601)."
          }
        },
        "description": "One event delivery to a webhook endpoint, without the event body that was sent.",
        "required": [
          "id",
          "endpointId",
          "eventType",
          "eventId",
          "status",
          "attempts",
          "responseStatus",
          "error",
          "lastAttemptAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "WebhookDeliveryListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The deliveries on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDeliveryEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "Number of deliveries matching the filter, across every page."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "Page size applied (1 to 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Number of deliveries skipped before this page."
          }
        },
        "description": "One page of an endpoint's delivery attempts, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "SummaryTotalsEntity": {
        "type": "object",
        "properties": {
          "all": {
            "type": "number",
            "description": "Every payment intent, any status.",
            "example": 137
          },
          "succeeded": {
            "type": "number",
            "description": "Payment intents in status `SUCCEEDED` (confirmed on their chain).",
            "example": 120
          },
          "pending": {
            "type": "number",
            "description": "Payment intents in status `PENDING` (created, awaiting payment).",
            "example": 9
          },
          "submitted": {
            "type": "number",
            "description": "Payment intents in status `SUBMITTED`: a signed transaction hash was reported, not yet confirmed.",
            "example": 3
          },
          "failed": {
            "type": "number",
            "description": "Payment intents in status `FAILED` (rejected on the network).",
            "example": 4
          },
          "cancelled": {
            "type": "number",
            "description": "Payment intents in status `CANCELLED`.",
            "example": 1
          },
          "expired": {
            "type": "number",
            "description": "Payment intents in status `EXPIRED` (unpaid past their expiry).",
            "example": 0
          },
          "successRate": {
            "type": "number",
            "description": "Succeeded ÷ all, as a percentage rounded to one decimal.",
            "example": 87.6
          }
        },
        "description": "Counts of the consumer's payment intents per status on the API key's network, with no date bound.",
        "required": [
          "all",
          "succeeded",
          "pending",
          "submitted",
          "failed",
          "cancelled",
          "expired",
          "successRate"
        ]
      },
      "AssetVolumeEntity": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "description": "Chain the payments settled on.",
            "example": "stellar"
          },
          "asset": {
            "type": "string",
            "description": "The chain’s coin (XLM, SOL, MON) for `native`, else the code.",
            "example": "XLM"
          },
          "amount": {
            "type": "string",
            "description": "Exact decimal string. Summed as `numeric` in PostgreSQL and never round-tripped through a float, so seven-decimal Stellar amounts are exact.",
            "example": "10420.5"
          },
          "count": {
            "type": "number",
            "description": "Settled payment intents in this chain and asset.",
            "example": 42
          },
          "amountUsd": {
            "type": "string",
            "nullable": true,
            "description": "`amount` in USD with two decimals, valued at NEAR Intents’ current reference price for each asset (its token list, cached for a few minutes): an indicative figure at today's price, not the price on the day each payment settled. A mainnet token is priced by its contract (on Stellar its code and issuer), so a token NEAR Intents does not list has no price; a test-network token takes the price of its mainnet namesake. When the code comes from several issuers, only the priced ones are added. Null when none is priced, or when the prices could not be read.",
            "example": "10418.42"
          }
        },
        "description": "Settled payment volume for one chain and asset, over every settled payment intent.",
        "required": [
          "chain",
          "asset",
          "amount",
          "count",
          "amountUsd"
        ]
      },
      "WebhookHealthEntity": {
        "type": "object",
        "properties": {
          "endpoints": {
            "type": "number",
            "description": "Webhook endpoints the consumer has registered.",
            "example": 3
          },
          "deliveries": {
            "type": "number",
            "description": "Deliveries to those endpoints, any status.",
            "example": 1204
          },
          "failedDeliveries": {
            "type": "number",
            "description": "Of those, the deliveries in status `FAILED`.",
            "example": 7
          }
        },
        "description": "The consumer's webhook endpoints and their deliveries. Not scoped by network: an endpoint belongs to none.",
        "required": [
          "endpoints",
          "deliveries",
          "failedDeliveries"
        ]
      },
      "SeriesPointEntity": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "The UTC day, `YYYY-MM-DD`.",
            "example": "2026-06-21"
          },
          "count": {
            "type": "number",
            "description": "Payment intents created that day, any status.",
            "example": 12
          },
          "volume": {
            "type": "string",
            "description": "Settled amount of that day's payment intents, every asset added, as a decimal string.",
            "example": "842.75"
          }
        },
        "description": "One UTC day of the summary's 30-day payment series.",
        "required": [
          "date",
          "count",
          "volume"
        ]
      },
      "RecentPaymentEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Payment intent id.",
            "example": "clz9xpi00001"
          },
          "kind": {
            "type": "string",
            "description": "How the intent was built: `TX` (an unsigned transaction for a known payer) or `PAY` (no payer known up front).",
            "example": "PAY"
          },
          "status": {
            "type": "string",
            "description": "Payment intent status, always `SUCCEEDED` here.",
            "example": "SUCCEEDED"
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "description": "Chain the payment settled on.",
            "example": "stellar"
          },
          "amount": {
            "type": "object",
            "nullable": true,
            "description": "Amount as a decimal string in the asset's units. Null when the intent was created without one (a `PAY` intent may omit it).",
            "example": "25.5"
          },
          "asset": {
            "type": "string",
            "description": "Asset code, or the chain's coin (XLM, SOL, MON) for the native asset.",
            "example": "XLM"
          },
          "destination": {
            "type": "string",
            "description": "Payee account, in the chain's own address format.",
            "example": "GDEST…"
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the intent was created (ISO 8601 date-time).",
            "example": "2026-06-21T12:34:56.000Z"
          }
        },
        "description": "A settled payment intent, as the summary lists the latest ones.",
        "required": [
          "id",
          "kind",
          "status",
          "chain",
          "asset",
          "destination",
          "createdAt"
        ]
      },
      "AnalyticsSummaryEntity": {
        "type": "object",
        "properties": {
          "totals": {
            "description": "Payment intent counts per status.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SummaryTotalsEntity"
              }
            ]
          },
          "volume": {
            "description": "Settled volume per chain and asset.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetVolumeEntity"
            }
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "Every settled payment in USD with two decimals, valued at NEAR Intents’ current reference price for each asset (its token list, cached for a few minutes): an indicative figure at today's price, not the price on the day each payment settled. Payments in an asset with no price are left out and counted in `unpriced`. Null only when there were settled payments and NEAR Intents' prices could not be read; `0.00` when nothing settled.",
            "example": "12843.17"
          },
          "unpriced": {
            "type": "number",
            "description": "Settled payments `volumeUsd` leaves out: their asset has no USD price (all of them when NEAR Intents' prices could not be read).",
            "example": 0
          },
          "webhooks": {
            "description": "Webhook endpoints and deliveries of the consumer.",
            "allOf": [
              {
                "$ref": "#/components/schemas/WebhookHealthEntity"
              }
            ]
          },
          "customers": {
            "type": "number",
            "description": "Distinct paying accounts.",
            "example": 58
          },
          "series": {
            "description": "30 daily buckets, pre-seeded so a quiet day is a zero.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SeriesPointEntity"
            }
          },
          "recent": {
            "description": "The 6 most recently created settled payment intents, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/RecentPaymentEntity"
            }
          }
        },
        "description": "Overview of the consumer's payment intents on the API key's network: counts per status, settled volume per asset and in USD, webhook health, distinct payers, a 30-day daily series and the latest settled payments.",
        "required": [
          "totals",
          "volume",
          "volumeUsd",
          "unpriced",
          "webhooks",
          "customers",
          "series",
          "recent"
        ]
      },
      "SeriesBucketEntity": {
        "type": "object",
        "properties": {
          "start": {
            "type": "string",
            "description": "The first day of the bucket (UTC; weeks start on Monday).",
            "example": "2026-10-01"
          },
          "count": {
            "type": "number",
            "description": "Payments created in the bucket, any status.",
            "example": 31
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones settled (status `SUCCEEDED`).",
            "example": 27
          },
          "failed": {
            "type": "number",
            "description": "Failed, cancelled or expired.",
            "example": 3
          },
          "volume": {
            "type": "string",
            "description": "Settled volume, every asset added.",
            "example": "1842.5"
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The bucket's settled payments in USD with two decimals, valued at NEAR Intents’ current reference price for each asset (its token list, cached for a few minutes): an indicative figure at today's price, not the price on the day each payment settled. Payments in an asset with no price add nothing (the window's `unpriced` counts them). Null only when the bucket has settled payments and NEAR Intents' prices could not be read.",
            "example": "1790.36"
          }
        },
        "description": "Payment intents created in one bucket of the series.",
        "required": [
          "start",
          "count",
          "succeeded",
          "failed",
          "volume",
          "volumeUsd"
        ]
      },
      "SeriesTotalsEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Payment intents created in the window, any status.",
            "example": 284
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones settled (status `SUCCEEDED`).",
            "example": 251
          },
          "failed": {
            "type": "number",
            "description": "Of those, the ones failed, cancelled or expired.",
            "example": 19
          },
          "volume": {
            "type": "string",
            "description": "Settled amount of those payment intents, every asset added, as a decimal string.",
            "example": "17410.25"
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The window's settled payments in USD with two decimals, valued at NEAR Intents’ current reference price for each asset (its token list, cached for a few minutes): an indicative figure at today's price, not the price on the day each payment settled. Null only when the window has settled payments and NEAR Intents' prices could not be read.",
            "example": "16982.04"
          },
          "unpriced": {
            "type": "number",
            "description": "Settled payments of the window `volumeUsd` leaves out: their asset has no USD price (all of them when NEAR Intents' prices could not be read).",
            "example": 0
          },
          "payers": {
            "type": "number",
            "description": "Distinct paying accounts in the window.",
            "example": 96
          }
        },
        "description": "Payment intent totals for the window the buckets cover, with its distinct payers.",
        "required": [
          "count",
          "succeeded",
          "failed",
          "volume",
          "volumeUsd",
          "unpriced",
          "payers"
        ]
      },
      "SeriesWindowEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Payment intents created in the window, any status.",
            "example": 284
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones settled (status `SUCCEEDED`).",
            "example": 251
          },
          "failed": {
            "type": "number",
            "description": "Of those, the ones failed, cancelled or expired.",
            "example": 19
          },
          "volume": {
            "type": "string",
            "description": "Settled amount of those payment intents, every asset added, as a decimal string.",
            "example": "17410.25"
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The window's settled payments in USD with two decimals, valued at NEAR Intents’ current reference price for each asset (its token list, cached for a few minutes): an indicative figure at today's price, not the price on the day each payment settled. Null only when the window has settled payments and NEAR Intents' prices could not be read.",
            "example": "16982.04"
          },
          "unpriced": {
            "type": "number",
            "description": "Settled payments of the window `volumeUsd` leaves out: their asset has no USD price (all of them when NEAR Intents' prices could not be read).",
            "example": 0
          }
        },
        "description": "Payment intent totals for a whole window of the series.",
        "required": [
          "count",
          "succeeded",
          "failed",
          "volume",
          "volumeUsd",
          "unpriced"
        ]
      },
      "SeriesSwapBucketEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Created in the bucket or window, any status.",
            "example": 42
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones that succeeded (for a USDT0 transfer, delivered).",
            "example": 37
          },
          "failed": {
            "type": "number",
            "description": "Given up on: failed or expired (and, for a cross-chain swap, refunded).",
            "example": 3
          },
          "start": {
            "type": "string",
            "description": "The first day of the bucket (UTC; weeks start on Monday), the same as the payments bucket at that index.",
            "example": "2026-10-01"
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The bucket’s settled swap volume in USD, two decimals: what the completed swaps sold, each asset at NEAR Intents' current price. Null when no price could be read; an asset with no price counts as zero.",
            "example": "1250.40"
          }
        },
        "description": "Swaps of every kind created in one bucket of the series, with the USD value of the completed ones.",
        "required": [
          "count",
          "succeeded",
          "failed",
          "start",
          "volumeUsd"
        ]
      },
      "SeriesSwapsByKindEntity": {
        "type": "object",
        "properties": {
          "dex": {
            "type": "number",
            "description": "Stellar DEX swaps.",
            "example": 30
          },
          "chain": {
            "type": "number",
            "description": "Solana (Jupiter) and Monad (Kuru Flow) swaps. Mainnet only.",
            "example": 8
          },
          "crossChain": {
            "type": "number",
            "description": "Swaps between networks through NEAR Intents. Mainnet only.",
            "example": 4
          },
          "usdt0": {
            "type": "number",
            "description": "USDT0 sent from Stellar to an EVM network through LayerZero (`/v1/usdt0`). Mainnet only.",
            "example": 2
          }
        },
        "description": "A window's swaps split by kind, any status.",
        "required": [
          "dex",
          "chain",
          "crossChain",
          "usdt0"
        ]
      },
      "SeriesSwapTotalsEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Created in the bucket or window, any status.",
            "example": 42
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones that succeeded (for a USDT0 transfer, delivered).",
            "example": 37
          },
          "failed": {
            "type": "number",
            "description": "Given up on: failed or expired (and, for a cross-chain swap, refunded).",
            "example": 3
          },
          "inProgress": {
            "type": "number",
            "description": "Not final yet: unsigned, submitted (a USDT0 transfer LayerZero is still delivering included), or a cross-chain swap awaiting or processing its deposit.",
            "example": 2
          },
          "byKind": {
            "description": "The window’s swaps per kind, any status.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesSwapsByKindEntity"
              }
            ]
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The window’s settled swap volume in USD, two decimals: what the completed swaps sold, each asset at NEAR Intents' current price. Null when no price could be read; an asset with no price counts as zero.",
            "example": "1250.40"
          },
          "unpriced": {
            "type": "number",
            "description": "Completed swaps whose sold asset has no USD price (a network or token NEAR Intents does not list), left out of volumeUsd.",
            "example": 0
          }
        },
        "description": "Swap totals for the window the buckets cover: outcomes, split by kind and USD volume.",
        "required": [
          "count",
          "succeeded",
          "failed",
          "inProgress",
          "byKind",
          "volumeUsd",
          "unpriced"
        ]
      },
      "SeriesSwapPreviousEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Created in the bucket or window, any status.",
            "example": 42
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones that succeeded (for a USDT0 transfer, delivered).",
            "example": 37
          },
          "failed": {
            "type": "number",
            "description": "Given up on: failed or expired (and, for a cross-chain swap, refunded).",
            "example": 3
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The window before’s settled swap volume in USD, two decimals: what the completed swaps sold, each asset at NEAR Intents' current price. Null when no price could be read; an asset with no price counts as zero.",
            "example": "1250.40"
          }
        },
        "description": "Swap totals for the window of the same length just before the current one, for growth.",
        "required": [
          "count",
          "succeeded",
          "failed",
          "volumeUsd"
        ]
      },
      "SeriesSwapsEntity": {
        "type": "object",
        "properties": {
          "buckets": {
            "description": "Swaps of every kind per bucket, on the same buckets as the payments, pre-seeded so a quiet bucket is a zero.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SeriesSwapBucketEntity"
            }
          },
          "totals": {
            "description": "The window the buckets cover.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesSwapTotalsEntity"
              }
            ]
          },
          "previous": {
            "description": "The window of the same length just before it, for growth.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesSwapPreviousEntity"
              }
            ]
          }
        },
        "description": "Swaps of every kind (Stellar DEX, Solana and Monad, cross-chain, USDT0 transfers) per bucket, with the totals of the window and of the window before.",
        "required": [
          "buckets",
          "totals",
          "previous"
        ]
      },
      "SeriesLiquidityBucketEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Created in the bucket or window, any status.",
            "example": 42
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones that succeeded (for a USDT0 transfer, delivered).",
            "example": 37
          },
          "failed": {
            "type": "number",
            "description": "Given up on: failed or expired (and, for a cross-chain swap, refunded).",
            "example": 3
          },
          "start": {
            "type": "string",
            "description": "The first day of the bucket (UTC; weeks start on Monday), the same as the payments bucket at that index.",
            "example": "2026-10-01"
          }
        },
        "description": "Liquidity pool deposits and withdrawals created in one bucket of the series.",
        "required": [
          "count",
          "succeeded",
          "failed",
          "start"
        ]
      },
      "SeriesOutcomeCountsEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Created in the bucket or window, any status.",
            "example": 42
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones that succeeded (for a USDT0 transfer, delivered).",
            "example": 37
          },
          "failed": {
            "type": "number",
            "description": "Given up on: failed or expired (and, for a cross-chain swap, refunded).",
            "example": 3
          }
        },
        "description": "Swaps or liquidity operations by outcome, for a bucket or a window of the series.",
        "required": [
          "count",
          "succeeded",
          "failed"
        ]
      },
      "SeriesLiquidityEntity": {
        "type": "object",
        "properties": {
          "buckets": {
            "description": "Liquidity pool deposits and withdrawals per bucket, on the same buckets as the payments, pre-seeded so a quiet bucket is a zero.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SeriesLiquidityBucketEntity"
            }
          },
          "totals": {
            "description": "Liquidity pool deposits and withdrawals in the window.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesOutcomeCountsEntity"
              }
            ]
          },
          "previous": {
            "description": "The window of the same length just before it, for growth.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesOutcomeCountsEntity"
              }
            ]
          }
        },
        "description": "Liquidity pool deposits and withdrawals per bucket, with the totals of the window and of the window before.",
        "required": [
          "buckets",
          "totals",
          "previous"
        ]
      },
      "SeriesWebhookBucketEntity": {
        "type": "object",
        "properties": {
          "start": {
            "type": "string",
            "description": "The first day of the bucket (UTC; weeks start on Monday), the same as the payments bucket at that index.",
            "example": "2026-10-01"
          },
          "deliveries": {
            "type": "number",
            "description": "Deliveries created in the bucket, any status.",
            "example": 26
          },
          "failed": {
            "type": "number",
            "description": "Of those, the ones whose last attempt failed, as GET /v1/summary counts them.",
            "example": 1
          }
        },
        "description": "Webhook deliveries created in one bucket of the series.",
        "required": [
          "start",
          "deliveries",
          "failed"
        ]
      },
      "SeriesWebhookCountsEntity": {
        "type": "object",
        "properties": {
          "deliveries": {
            "type": "number",
            "description": "Deliveries created in the window, any status.",
            "example": 310
          },
          "failed": {
            "type": "number",
            "description": "Of those, the ones whose last attempt failed, as GET /v1/summary counts them (the sweeper may still redeliver one).",
            "example": 4
          }
        },
        "description": "Webhook deliveries created in a window of the series.",
        "required": [
          "deliveries",
          "failed"
        ]
      },
      "SeriesWebhooksEntity": {
        "type": "object",
        "properties": {
          "buckets": {
            "description": "Deliveries per bucket, on the same buckets as the payments, pre-seeded so a quiet bucket is a zero.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SeriesWebhookBucketEntity"
            }
          },
          "totals": {
            "description": "Deliveries to every endpoint of the consumer in the window. Not scoped by network: an endpoint belongs to none.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesWebhookCountsEntity"
              }
            ]
          },
          "previous": {
            "description": "The window of the same length just before it, for growth.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesWebhookCountsEntity"
              }
            ]
          }
        },
        "description": "Webhook deliveries to the consumer's endpoints per bucket, with the totals of the window and of the window before.",
        "required": [
          "buckets",
          "totals",
          "previous"
        ]
      },
      "SeriesPrivatePaymentBucketEntity": {
        "type": "object",
        "properties": {
          "start": {
            "type": "string",
            "description": "The first day of the bucket (UTC; weeks start on Monday), the same as the payments bucket at that index.",
            "example": "2026-10-01"
          },
          "count": {
            "type": "number",
            "description": "Private payments created in the bucket, any status.",
            "example": 12
          },
          "succeeded": {
            "type": "number",
            "description": "Settled: both transfers confirmed.",
            "example": 9
          },
          "expired": {
            "type": "number",
            "description": "Past their deadline without settling (a pending payment reads as expired once its deadline passes).",
            "example": 2
          },
          "volume": {
            "type": "string",
            "description": "Settled amount in XLM, what the payers paid (the commission included).",
            "example": "450.5"
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The bucket's settled amount in USD with two decimals, valued at XLM's current reference price on NEAR Intents (an indicative figure at today's price). Null only when there is something settled and NEAR Intents' prices could not be read.",
            "example": "112.63"
          }
        },
        "description": "Private payments created in one bucket of the series, amounts in XLM.",
        "required": [
          "start",
          "count",
          "succeeded",
          "expired",
          "volume",
          "volumeUsd"
        ]
      },
      "SeriesPrivatePaymentWindowEntity": {
        "type": "object",
        "properties": {
          "count": {
            "type": "number",
            "description": "Private payments created in the window, any status.",
            "example": 48
          },
          "succeeded": {
            "type": "number",
            "description": "Of those, the ones settled (status `SUCCEEDED`).",
            "example": 41
          },
          "expired": {
            "type": "number",
            "description": "Past their deadline without settling (a pending payment reads as expired once its deadline passes).",
            "example": 5
          },
          "volume": {
            "type": "string",
            "description": "Settled amount in XLM, what the payers paid (the commission included).",
            "example": "2140.25"
          },
          "volumeUsd": {
            "type": "string",
            "nullable": true,
            "description": "The window's settled amount in USD with two decimals, valued at XLM's current reference price on NEAR Intents (an indicative figure at today's price). Null only when there is something settled and NEAR Intents' prices could not be read.",
            "example": "535.06"
          },
          "fees": {
            "type": "string",
            "description": "Commission the settled payments paid to Cosmos Pay, in XLM (0.18% of each).",
            "example": "0.214025"
          },
          "feesUsd": {
            "type": "string",
            "nullable": true,
            "description": "The window's commission in USD with two decimals, valued at XLM's current reference price on NEAR Intents (an indicative figure at today's price). Null only when there is something settled and NEAR Intents' prices could not be read.",
            "example": "0.05"
          }
        },
        "description": "Private payment totals for a window of the series, amounts in XLM.",
        "required": [
          "count",
          "succeeded",
          "expired",
          "volume",
          "volumeUsd",
          "fees",
          "feesUsd"
        ]
      },
      "SeriesPrivatePaymentsEntity": {
        "type": "object",
        "properties": {
          "buckets": {
            "description": "Private payments per bucket, on the same buckets as the payments, pre-seeded so a quiet bucket is a zero.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SeriesPrivatePaymentBucketEntity"
            }
          },
          "totals": {
            "description": "The window the buckets cover.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesPrivatePaymentWindowEntity"
              }
            ]
          },
          "previous": {
            "description": "The window of the same length just before it, for growth.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesPrivatePaymentWindowEntity"
              }
            ]
          }
        },
        "description": "Private payments per bucket, with the totals of the window and of the window before; amounts in XLM.",
        "required": [
          "buckets",
          "totals",
          "previous"
        ]
      },
      "AnalyticsSeriesEntity": {
        "type": "object",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "day",
              "week",
              "month",
              "year"
            ],
            "description": "How the buckets are grouped, as requested (`day` when omitted).",
            "example": "month"
          },
          "buckets": {
            "description": "30 days, 12 weeks, 12 months or 5 years, oldest first, pre-seeded so a quiet bucket is a zero.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SeriesBucketEntity"
            }
          },
          "totals": {
            "description": "The window the buckets cover.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesTotalsEntity"
              }
            ]
          },
          "previous": {
            "description": "The window of the same length just before it, for growth.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesWindowEntity"
              }
            ]
          },
          "swaps": {
            "description": "Swaps of every kind (Stellar DEX, Solana and Monad, cross-chain, USDT0 sent through LayerZero) on the network the key targets: a sandbox key counts no Solana, Monad, cross-chain swap or USDT0 transfer, which run on mainnet only.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesSwapsEntity"
              }
            ]
          },
          "liquidity": {
            "description": "Liquidity pool operations on the network the key targets.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesLiquidityEntity"
              }
            ]
          },
          "webhooks": {
            "description": "Webhook deliveries to the consumer’s endpoints.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesWebhooksEntity"
              }
            ]
          },
          "zkPayments": {
            "description": "Private payments (amounts hidden on-chain, /v1/zk-payments) on the network the key targets. They run on testnet only for now, so a production key counts none.",
            "allOf": [
              {
                "$ref": "#/components/schemas/SeriesPrivatePaymentsEntity"
              }
            ]
          }
        },
        "description": "The consumer's payments, swaps, liquidity operations, webhook deliveries and private payments grouped into UTC buckets of `period` (weeks start on Monday), with the totals of the window and of the window before.",
        "required": [
          "period",
          "buckets",
          "totals",
          "previous",
          "swaps",
          "liquidity",
          "webhooks",
          "zkPayments"
        ]
      },
      "AssetBalanceEntity": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "description": "Chain the payment intents are on.",
            "example": "stellar"
          },
          "asset": {
            "type": "string",
            "description": "Asset code, or the chain's coin (XLM, SOL, MON) for the native asset.",
            "example": "XLM"
          },
          "amount": {
            "type": "string",
            "description": "Settled.",
            "example": "10420.5"
          },
          "pending": {
            "type": "string",
            "description": "In flight.",
            "example": "120"
          },
          "count": {
            "type": "number",
            "description": "Settled payment intents in this chain and asset.",
            "example": 42
          }
        },
        "description": "Settled and in-flight payment intent amounts for one chain and asset.",
        "required": [
          "chain",
          "asset",
          "amount",
          "pending",
          "count"
        ]
      },
      "AnalyticsBalancesEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "One entry per chain and asset, largest settled amount first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AssetBalanceEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Number of entries in `data` (the list is not paged).",
            "example": 3
          }
        },
        "description": "Settled and pending payment intent amounts per chain and asset, on the API key's network.",
        "required": [
          "data",
          "total"
        ]
      },
      "ApiLogEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Request log id.",
            "example": "clz9xlog00001"
          },
          "method": {
            "type": "string",
            "description": "HTTP method.",
            "example": "POST"
          },
          "path": {
            "type": "string",
            "description": "Request path, without the query string.",
            "example": "/v1/swaps"
          },
          "statusCode": {
            "type": "number",
            "description": "HTTP status code of the response.",
            "example": 201
          },
          "durationMs": {
            "type": "number",
            "description": "Time this service took to handle the request, in milliseconds.",
            "example": 84
          },
          "ip": {
            "type": "object",
            "nullable": true,
            "description": "Client IP address, as this service saw it.",
            "example": "203.0.113.7"
          },
          "userAgent": {
            "type": "object",
            "nullable": true,
            "description": "The request's `User-Agent` header. Null when it sent none.",
            "example": "curl/8.4.0"
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "pending",
              "fail"
            ],
            "description": "`ok` below 400, `pending` for a 4xx and `fail` for a 5xx.",
            "example": "ok"
          },
          "at": {
            "format": "date-time",
            "type": "string",
            "description": "When the request was logged (ISO 8601 date-time).",
            "example": "2026-06-21T12:34:56.000Z"
          }
        },
        "description": "One API request of the consumer, as this service logged it. The dashboard's own console calls are left out.",
        "required": [
          "id",
          "method",
          "path",
          "statusCode",
          "durationMs",
          "status",
          "at"
        ]
      },
      "ApiLogListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The requests of this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ApiLogEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Total matching rows, not the page length.",
            "example": 41203
          },
          "take": {
            "type": "number",
            "description": "The page size applied (the `take` query parameter).",
            "example": 100
          },
          "skip": {
            "type": "number",
            "description": "Rows skipped before this page (the `skip` query parameter).",
            "example": 0
          }
        },
        "description": "A page of the consumer's API request log, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "WebhookLogEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Webhook delivery id.",
            "example": "clz9xwd00001"
          },
          "endpointId": {
            "type": "string",
            "description": "Id of the webhook endpoint the delivery is for.",
            "example": "we_9z8a1b0000abcd1234efgh"
          },
          "url": {
            "type": "object",
            "nullable": true,
            "description": "The endpoint's URL.",
            "example": "https://acme.test/hooks"
          },
          "eventType": {
            "type": "string",
            "description": "Type of the event delivered.",
            "example": "PAYMENT_INTENT_SUCCEEDED"
          },
          "eventId": {
            "type": "string",
            "description": "Stable id of the event, sent to the receiver for idempotency.",
            "example": "evt_2c3d4e5f-aaaa-bbbb-cccc-1234567890ab"
          },
          "attempts": {
            "type": "number",
            "description": "Delivery attempts made.",
            "example": 1
          },
          "responseStatus": {
            "type": "object",
            "nullable": true,
            "description": "HTTP status the endpoint answered on the last attempt. Null when no attempt has finished or the last one got no response.",
            "example": 200
          },
          "error": {
            "type": "object",
            "nullable": true,
            "description": "Why the last attempt failed. Null when the delivery succeeded or no attempt has finished.",
            "example": null
          },
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "pending",
              "fail"
            ],
            "description": "`ok` when delivered, `fail` when failed, `pending` otherwise.",
            "example": "ok"
          },
          "at": {
            "format": "date-time",
            "type": "string",
            "description": "When the delivery was last attempted, or when it was created if never (ISO 8601 date-time).",
            "example": "2026-06-21T12:34:57.000Z"
          }
        },
        "description": "One webhook delivery to one of the consumer's endpoints. The payload is never included.",
        "required": [
          "id",
          "endpointId",
          "eventType",
          "eventId",
          "attempts",
          "status",
          "at"
        ]
      },
      "WebhookLogListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The deliveries of this page, newest created first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookLogEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Total matching rows, not the page length.",
            "example": 1204
          },
          "take": {
            "type": "number",
            "description": "The page size applied (the `take` query parameter).",
            "example": 100
          },
          "skip": {
            "type": "number",
            "description": "Rows skipped before this page (the `skip` query parameter).",
            "example": 0
          }
        },
        "description": "A page of the webhook deliveries to every endpoint of the consumer, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "ActivityEventDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Event name, e.g. `payment.sent`. Lowercase, dot/underscore/dash/colon separated.",
            "example": "payment.sent"
          },
          "eventId": {
            "type": "string",
            "description": "The client's own id for this event. Send one to make a flush retry safe: a batch that was written but never acknowledged can be re-sent without doubling its rows.",
            "example": "6f1a2b3c-4d5e-4f60-8a1b-2c3d4e5f6071"
          },
          "source": {
            "type": "string",
            "enum": [
              "wallet",
              "dashboard",
              "server",
              "sdk"
            ],
            "default": "sdk",
            "description": "Which client reports the event."
          },
          "level": {
            "type": "string",
            "enum": [
              "debug",
              "info",
              "warn",
              "error"
            ],
            "default": "info",
            "description": "Severity of the event, from `debug` up to `error`."
          },
          "category": {
            "type": "string",
            "description": "Coarse grouping: error, metric, transaction, auth, navigation, api, lifecycle, ui.",
            "example": "transaction",
            "default": "event"
          },
          "message": {
            "type": "string",
            "description": "Human-readable detail. Truncated rather than rejected when long: a telemetry call must not fail on the size of an error string.",
            "example": "op_no_trust"
          },
          "sessionId": {
            "type": "string",
            "description": "Anonymous id grouping one run of the app. Not an account id."
          },
          "distinctId": {
            "type": "string",
            "description": "Anonymous id for one install. Not an account id."
          },
          "appVersion": {
            "type": "string",
            "description": "Version of the app reporting the event.",
            "example": "1.5.0"
          },
          "platform": {
            "type": "string",
            "description": "web | ext | app | desktop | dashboard | node",
            "example": "ext"
          },
          "network": {
            "type": "string",
            "description": "Network the event happened on, when it had one.",
            "example": "testnet"
          },
          "durationMs": {
            "type": "number",
            "description": "Duration of the measured operation, for a timing metric.",
            "example": 812
          },
          "props": {
            "type": "object",
            "description": "Structured detail. Size-capped at ingest; never credentials, never a seed.",
            "additionalProperties": true,
            "example": {
              "asset": "XLM",
              "amount": "12.5"
            }
          },
          "occurredAt": {
            "type": "string",
            "description": "When the client says it happened. Clamped to the receipt time when the device clock is too far off. Defaults to receipt time.",
            "example": "2026-09-06T12:34:56.000Z"
          }
        },
        "description": "One client event to report. `type` and `category` are free-form names; `source` and `level` are closed lists.",
        "required": [
          "type"
        ]
      },
      "IngestActivityDto": {
        "type": "object",
        "properties": {
          "events": {
            "description": "Up to 100 events. Clients batch: a wallet queues while offline and flushes on the next launch.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityEventDto"
            }
          }
        },
        "description": "A batch of client events to record under the calling consumer.",
        "required": [
          "events"
        ]
      },
      "ActivityIngestResultEntity": {
        "type": "object",
        "properties": {
          "accepted": {
            "type": "number",
            "description": "Events written.",
            "example": 24
          },
          "duplicates": {
            "type": "number",
            "description": "Events dropped as duplicates of a batch already written. Never an error: a client that retries a flush it never saw acknowledged is doing the right thing.",
            "example": 0
          }
        },
        "description": "What an ingest call wrote: the events accepted and the duplicates skipped.",
        "required": [
          "accepted",
          "duplicates"
        ]
      },
      "ActivityEventEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "Event id assigned by this service.",
            "example": "clz9xact00001"
          },
          "source": {
            "type": "string",
            "description": "Which client reported the event: `wallet`, `dashboard`, `server` or `sdk` (`sdk` when it sent none).",
            "example": "wallet"
          },
          "level": {
            "type": "string",
            "description": "Severity: `debug`, `info`, `warn` or `error` (`info` when the client sent none).",
            "example": "error"
          },
          "category": {
            "type": "string",
            "description": "Coarse grouping the client gave the event (`event` when it sent none).",
            "example": "transaction"
          },
          "type": {
            "type": "string",
            "description": "Event name, e.g. `payment.sent`.",
            "example": "payment.sent"
          },
          "message": {
            "type": "object",
            "nullable": true,
            "description": "Human-readable detail, cut to 500 characters at ingest. Null when the client sent none.",
            "example": "op_no_trust"
          },
          "sessionId": {
            "type": "object",
            "nullable": true,
            "description": "Anonymous id grouping one run of the app, as the client sent it. Not an account id.",
            "example": "s_9f2a1c"
          },
          "distinctId": {
            "type": "object",
            "nullable": true,
            "description": "Anonymous id for one install, as the client sent it. Not an account id.",
            "example": "d_41b0c8"
          },
          "appVersion": {
            "type": "object",
            "nullable": true,
            "description": "Version of the app that reported the event.",
            "example": "1.5.0"
          },
          "platform": {
            "type": "object",
            "nullable": true,
            "description": "Platform the client runs on, as it sent it (e.g. `web`, `ext`, `app`, `desktop`, `dashboard`, `node`).",
            "example": "ext"
          },
          "network": {
            "type": "object",
            "nullable": true,
            "description": "Network the event happened on, as the client sent it.",
            "example": "testnet"
          },
          "durationMs": {
            "type": "object",
            "nullable": true,
            "description": "Duration of the measured operation in milliseconds, for a timing metric.",
            "example": 812
          },
          "props": {
            "type": "object",
            "nullable": true,
            "additionalProperties": true,
            "description": "Structured detail the client attached. `{ \"_dropped\": \"props_too_large\" }` when it was over 8,192 bytes serialized.",
            "example": {
              "asset": "XLM",
              "amount": "12.5"
            }
          },
          "ip": {
            "type": "object",
            "nullable": true,
            "description": "IP address of the client that reported the event.",
            "example": "203.0.113.7"
          },
          "userAgent": {
            "type": "object",
            "nullable": true,
            "description": "The reporting request's `User-Agent` header, cut to 300 characters.",
            "example": "CosmosWallet/1.5.0"
          },
          "at": {
            "format": "date-time",
            "type": "string",
            "description": "When the client says it happened.",
            "example": "2026-09-06T12:34:56.000Z"
          },
          "receivedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When this service received it (later for a queued batch).",
            "example": "2026-09-06T12:35:10.000Z"
          }
        },
        "description": "One client event the consumer reported, as stored.",
        "required": [
          "id",
          "source",
          "level",
          "category",
          "type",
          "at",
          "receivedAt"
        ]
      },
      "ActivityEventListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The events of this page, newest first by `at`.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityEventEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Total matching rows, not the page length.",
            "example": 4120
          },
          "take": {
            "type": "number",
            "description": "The page size applied (the `take` query parameter).",
            "example": 100
          },
          "skip": {
            "type": "number",
            "description": "Rows skipped before this page (the `skip` query parameter).",
            "example": 0
          }
        },
        "description": "A page of the consumer's client events matching the filters, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "ActivityCountEntity": {
        "type": "object",
        "properties": {
          "key": {
            "type": "string",
            "description": "The value counted: a level, source, category, event type or error message, depending on the list.",
            "example": "error"
          },
          "count": {
            "type": "number",
            "description": "Events in the window with that value.",
            "example": 12
          }
        },
        "description": "The number of events in the window with one value of a field.",
        "required": [
          "key",
          "count"
        ]
      },
      "ActivitySeriesPointEntity": {
        "type": "object",
        "properties": {
          "date": {
            "type": "string",
            "description": "The UTC day, `YYYY-MM-DD`.",
            "example": "2026-09-06"
          },
          "count": {
            "type": "number",
            "description": "Events in the window that occurred that day (by `at`).",
            "example": 128
          },
          "errors": {
            "type": "number",
            "description": "Of those, the events at level `error`.",
            "example": 4
          }
        },
        "description": "Client events on one UTC day of the rollup window.",
        "required": [
          "date",
          "count",
          "errors"
        ]
      },
      "ActivitySummaryEntity": {
        "type": "object",
        "properties": {
          "total": {
            "type": "number",
            "description": "Events in the window.",
            "example": 4120
          },
          "sessions": {
            "type": "number",
            "description": "Distinct `sessionId`s in the window: app runs, not accounts.",
            "example": 318
          },
          "devices": {
            "type": "number",
            "description": "Distinct `distinctId`s in the window: installs, not accounts.",
            "example": 96
          },
          "levels": {
            "description": "Count per level.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityCountEntity"
            }
          },
          "sources": {
            "description": "Count per source.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityCountEntity"
            }
          },
          "categories": {
            "description": "Count per category.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityCountEntity"
            }
          },
          "topTypes": {
            "description": "Most frequent event types.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityCountEntity"
            }
          },
          "topErrors": {
            "description": "Most frequent error messages: what to fix first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivityCountEntity"
            }
          },
          "series": {
            "description": "Daily buckets, pre-seeded so a quiet day is a zero.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ActivitySeriesPointEntity"
            }
          }
        },
        "description": "Rollup of the client events this consumer reported over the last `days` days, optionally for one `source`.",
        "required": [
          "total",
          "sessions",
          "devices",
          "levels",
          "sources",
          "categories",
          "topTypes",
          "topErrors",
          "series"
        ]
      },
      "CreateProductDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Pro plan (monthly)",
            "description": "Product name (1 to 120 characters)."
          },
          "description": {
            "type": "string",
            "example": "Full access, billed every month.",
            "description": "Free-text description of the product (at most 500 characters)."
          },
          "amount": {
            "type": "string",
            "example": "49.00",
            "description": "Decimal price (≤ 7 decimals). Omit for a customer-set amount."
          },
          "assetCode": {
            "type": "string",
            "example": "USDC",
            "description": "Asset code the price is in. Omit for native lumens (XLM)."
          },
          "kind": {
            "type": "string",
            "enum": [
              "recurring",
              "one_time",
              "link"
            ],
            "default": "one_time",
            "description": "Informational classification: `one_time` (default), `recurring` or `link`."
          },
          "active": {
            "type": "boolean",
            "default": true,
            "description": "Whether the product is active. `false` retires it and keeps its record."
          },
          "reference": {
            "type": "string",
            "example": "sku_pro_monthly",
            "description": "Your own SKU or reference for the product (at most 120 characters)."
          }
        },
        "description": "A catalog product to create. Creating one builds no payment link or intent.",
        "required": [
          "name"
        ]
      },
      "ProductEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "Product id."
          },
          "name": {
            "type": "string",
            "example": "Pro plan (monthly)",
            "description": "Product name."
          },
          "description": {
            "type": "object",
            "nullable": true,
            "example": "Full access, billed every month.",
            "description": "Description of the product; null when none was given."
          },
          "amount": {
            "type": "object",
            "nullable": true,
            "example": "49.00",
            "description": "Price as a decimal string in `asset`; null for a customer-set amount."
          },
          "asset": {
            "type": "string",
            "example": "native",
            "description": "Asset code, or \"native\" for XLM."
          },
          "kind": {
            "type": "string",
            "example": "one_time",
            "enum": [
              "recurring",
              "one_time",
              "link"
            ],
            "description": "Informational classification: `recurring`, `one_time` or `link`."
          },
          "active": {
            "type": "boolean",
            "example": true,
            "description": "Whether the product is active; inactive products are kept and still listed."
          },
          "reference": {
            "type": "object",
            "nullable": true,
            "example": "sku_pro_monthly",
            "description": "Your own SKU or reference; null when none was given."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the product was created (ISO 8601)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the product last changed (ISO 8601)."
          }
        },
        "description": "A catalog product of the consumer: a name, an optional price and an informational kind.",
        "required": [
          "id",
          "name",
          "description",
          "amount",
          "asset",
          "kind",
          "active",
          "reference",
          "createdAt",
          "updatedAt"
        ]
      },
      "ProductListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The products on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProductEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 137,
            "description": "Total products matching the query, not the page size."
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "Page size applied (1 to 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Number of products skipped before this page."
          }
        },
        "description": "One page of the consumer's products, newest first, inactive ones included.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "UpdateProductDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Pro plan (monthly)",
            "description": "Product name (1 to 120 characters)."
          },
          "description": {
            "type": "string",
            "example": "Full access, billed every month.",
            "description": "Free-text description of the product (at most 500 characters)."
          },
          "amount": {
            "type": "string",
            "example": "49.00",
            "description": "Decimal price (≤ 7 decimals). Omit for a customer-set amount."
          },
          "assetCode": {
            "type": "string",
            "example": "USDC",
            "description": "Asset code the price is in. Omit for native lumens (XLM)."
          },
          "kind": {
            "type": "string",
            "enum": [
              "recurring",
              "one_time",
              "link"
            ],
            "default": "one_time",
            "description": "Informational classification: `one_time` (default), `recurring` or `link`."
          },
          "active": {
            "type": "boolean",
            "default": true,
            "description": "Whether the product is active. `false` retires it and keeps its record."
          },
          "reference": {
            "type": "string",
            "example": "sku_pro_monthly",
            "description": "Your own SKU or reference for the product (at most 120 characters)."
          }
        },
        "description": "Changes to a product: any subset of the create fields; only the fields sent change."
      },
      "ProductDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "Id of the deleted product."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirmation that a product was deleted.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "AliasAddressEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The id of this address on the alias, as `DELETE /v1/aliases/{name}/addresses/{addressId}` takes it."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "The chain the address is on."
          },
          "address": {
            "type": "string",
            "description": "On `chain`: Stellar G…, Solana base58, Monad 0x… (EIP-55)."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Network id the address is on: public | testnet | a custom id."
          },
          "label": {
            "type": "object",
            "nullable": true,
            "description": "Human label the owner gave this address; null without one."
          },
          "isPrimary": {
            "type": "boolean",
            "description": "The default for this chain and network."
          },
          "verifiedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When this address proved control of itself."
          }
        },
        "description": "One verified address an alias resolves to, on one chain and network.",
        "required": [
          "id",
          "chain",
          "address",
          "network",
          "isPrimary",
          "verifiedAt"
        ]
      },
      "AliasResolutionEntity": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Normalized handle: the form uniqueness is decided on."
          },
          "displayName": {
            "type": "string",
            "description": "As the claimant typed it. Display only."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "description": "The chain resolved on: the one asked for, else Stellar."
          },
          "addresses": {
            "description": "Every verified address on the requested chain and network, primary first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AliasAddressEntity"
            }
          },
          "primaryAddress": {
            "type": "object",
            "nullable": true,
            "description": "The address to pay when the payer did not choose one."
          }
        },
        "description": "An alias resolved for a payer: its addresses on one chain, primary first, and nothing about its owner.",
        "required": [
          "name",
          "displayName",
          "chain",
          "addresses"
        ]
      },
      "AliasAvailabilityEntity": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The handle as checked: trimmed and lowercased."
          },
          "available": {
            "type": "boolean",
            "description": "Whether the handle can be claimed now."
          },
          "reason": {
            "type": "object",
            "nullable": true,
            "description": "Why not, when unavailable: taken, reserved, bad_characters, …"
          }
        },
        "description": "Whether a handle can be claimed now, and why not when it cannot. It reserves nothing.",
        "required": [
          "name",
          "available"
        ]
      },
      "AliasByAddressEntryEntity": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "alice",
            "description": "Normalized handle: the form uniqueness is decided on."
          },
          "displayName": {
            "type": "string",
            "example": "Alice",
            "description": "As the claimant typed it. Display only."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "The chain the address is on."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Network id the address is on: public | testnet | a custom id."
          },
          "isPrimary": {
            "type": "boolean",
            "description": "The default for this network."
          }
        },
        "description": "One active alias that holds an address, never who owns it.",
        "required": [
          "name",
          "displayName",
          "chain",
          "network",
          "isPrimary"
        ]
      },
      "AliasByAddressEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The active aliases holding the address, oldest first; empty when none does.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AliasByAddressEntryEntity"
            }
          }
        },
        "description": "The active aliases that hold an address, oldest first. Empty, never a 404, when none does.",
        "required": [
          "data"
        ]
      },
      "CreateAliasChallengeDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "emanuel250",
            "description": "The handle being claimed."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "Chain the address is on. Omit for Stellar. Stellar signs the challenge digest (ed25519); Solana signs the challenge text (ed25519, `signMessage`); Monad signs it with EIP-191 `personal_sign`."
          },
          "address": {
            "type": "string",
            "description": "The address on `chain`: Stellar G…, Solana base58, Monad 0x….",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Network id: public | testnet | a custom id."
          },
          "purpose": {
            "type": "string",
            "enum": [
              "CLAIM",
              "ADD_ADDRESS",
              "RECOVER"
            ],
            "default": "CLAIM",
            "description": "What the signature will be spent on: CLAIM (a new alias), ADD_ADDRESS (another address on an alias) or RECOVER (finishing an email recovery). Anything but CLAIM needs an existing alias."
          }
        },
        "description": "Request for a single-use challenge to sign: the handle, the address that will sign, its network and what the signature is for.",
        "required": [
          "name",
          "address",
          "network"
        ]
      },
      "AliasChallengeEntity": {
        "type": "object",
        "properties": {
          "nonce": {
            "type": "string",
            "description": "Send this back with the signature."
          },
          "message": {
            "type": "string",
            "description": "The EXACT string to sign: digested first on Stellar, signed as text on Solana and Monad. Returned rather than described so a client never rebuilds it from prose. A client that assembles the fields itself is one field-order change away from producing signatures nothing accepts."
          },
          "domain": {
            "type": "string",
            "description": "Domain tag the digest is framed with."
          },
          "purpose": {
            "type": "string",
            "enum": [
              "CLAIM",
              "ADD_ADDRESS",
              "RECOVER"
            ],
            "description": "What the signature can be spent on: the purpose the request asked for."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the challenge stops being spendable (ISO 8601 date-time), 5 minutes after it was issued."
          }
        },
        "description": "A single-use challenge to sign: send `nonce` back with the signature over `message` before `expiresAt`.",
        "required": [
          "nonce",
          "message",
          "domain",
          "purpose",
          "expiresAt"
        ]
      },
      "ClaimAliasDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "emanuel250",
            "description": "The handle being claimed: the one the challenge was issued for."
          },
          "email": {
            "type": "string",
            "description": "Recovery mailbox. Required at claim time, not later: an alias whose owner loses their key before adding one is unrecoverable, and that is the state this field exists to prevent.",
            "example": "someone@example.com"
          },
          "nonce": {
            "type": "string",
            "description": "The nonce from POST /v1/aliases/challenges."
          },
          "signature": {
            "type": "string",
            "description": "Stellar: base64 ed25519 over the challenge digest. Solana: base64 or base58 ed25519 over the challenge text. Monad: 0x-hex EIP-191 signature over the challenge text."
          },
          "label": {
            "type": "string",
            "description": "Human label for this first address.",
            "example": "phone"
          }
        },
        "description": "Request to claim an alias with a signature over a CLAIM challenge. The address, chain and network registered are the challenge's.",
        "required": [
          "name",
          "email",
          "nonce",
          "signature"
        ]
      },
      "OwnedAliasEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The alias id."
          },
          "name": {
            "type": "string",
            "description": "Normalized handle: the form uniqueness is decided on."
          },
          "displayName": {
            "type": "string",
            "description": "As the claimant typed it. Display only."
          },
          "status": {
            "type": "string",
            "enum": [
              "ACTIVE",
              "SUSPENDED"
            ],
            "description": "SUSPENDED when an operator holds the alias (an impersonation report, a dispute): a suspended alias does not resolve."
          },
          "addresses": {
            "description": "Every address of the alias, on every chain and network, primary first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AliasAddressEntity"
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the alias was claimed (ISO 8601 date-time)."
          },
          "email": {
            "type": "string",
            "example": "someone@example.com",
            "description": "The recovery mailbox, trimmed and lowercased."
          },
          "emailVerifiedAt": {
            "type": "object",
            "nullable": true,
            "description": "When the recovery mailbox was verified (ISO 8601 date-time); null while it is not."
          }
        },
        "description": "An alias as its owner sees it: the public fields plus the recovery mailbox, which resolution never returns.",
        "required": [
          "id",
          "name",
          "displayName",
          "status",
          "addresses",
          "createdAt",
          "email"
        ]
      },
      "AliasListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The aliases on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/OwnedAliasEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "How many aliases the caller holds, across all pages."
          },
          "take": {
            "type": "number",
            "description": "The page size this page was read with."
          },
          "skip": {
            "type": "number",
            "description": "How many aliases were skipped before this page."
          }
        },
        "description": "One page of the caller's aliases, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "AddAliasAddressDto": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "Chain the address is on. Omit for Stellar. Stellar signs the challenge digest (ed25519); Solana signs the challenge text (ed25519, `signMessage`); Monad signs it with EIP-191 `personal_sign`."
          },
          "address": {
            "type": "string",
            "description": "The address on `chain`: Stellar G…, Solana base58, Monad 0x…."
          },
          "network": {
            "type": "string",
            "example": "testnet",
            "description": "Network id the address is on (public | testnet | a custom id); it must be the challenge's."
          },
          "nonce": {
            "type": "string",
            "description": "The nonce from an ADD_ADDRESS challenge."
          },
          "signature": {
            "type": "string",
            "description": "Stellar: base64 ed25519 over the challenge digest. Solana: base64 or base58 ed25519 over the challenge text. Monad: 0x-hex EIP-191 signature over the challenge text."
          },
          "label": {
            "type": "string",
            "example": "cold wallet",
            "description": "Human label for this address."
          },
          "primary": {
            "type": "boolean",
            "description": "Make this the address a payer gets when they do not ask for a specific one on this network. Exactly one address per network is primary.",
            "default": false
          }
        },
        "description": "Request to add another address to an alias the caller holds, with that address's signature over an ADD_ADDRESS challenge.",
        "required": [
          "address",
          "network",
          "nonce",
          "signature"
        ]
      },
      "AliasDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The id of what was deleted: the alias on a release, the address on an address removal."
          },
          "deleted": {
            "type": "boolean",
            "description": "Always true."
          }
        },
        "description": "The answer to a delete: the id of the alias or address deleted.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "StartAliasRecoveryDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "description": "The mailbox on record. Checked but never echoed: the response is identical whether or not it matched, so this endpoint cannot be used to ask which address owns a handle.",
            "example": "someone@example.com"
          }
        },
        "description": "Request to start an alias's email recovery: when the mailbox matches, the token is emailed to it.",
        "required": [
          "email"
        ]
      },
      "AliasRecoveryStartedEntity": {
        "type": "object",
        "properties": {
          "accepted": {
            "type": "boolean",
            "example": true,
            "description": "Always true, whether or not anything matched. The token, when there is one, is emailed to the mailbox on record, never returned here."
          }
        },
        "description": "The answer to starting a recovery: the same whether or not the alias and the mailbox matched.",
        "required": [
          "accepted"
        ]
      },
      "CompleteAliasRecoveryDto": {
        "type": "object",
        "properties": {
          "token": {
            "type": "string",
            "description": "The token delivered by email."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "Chain the address is on. Omit for Stellar. Stellar signs the challenge digest (ed25519); Solana signs the challenge text (ed25519, `signMessage`); Monad signs it with EIP-191 `personal_sign`."
          },
          "address": {
            "type": "string",
            "description": "The address that will own the alias from now on, on `chain`: Stellar G…, Solana base58, Monad 0x…."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Network id the new address is on (public | testnet | a custom id); it must be the challenge's."
          },
          "nonce": {
            "type": "string",
            "description": "The nonce from a RECOVER challenge."
          },
          "signature": {
            "type": "string",
            "description": "Stellar: base64 ed25519 over the challenge digest. Solana: base64 or base58 ed25519 over the challenge text. Monad: 0x-hex EIP-191 signature over the challenge text."
          }
        },
        "description": "Request to finish an email recovery: the emailed token and a signature over a RECOVER challenge by the address that takes ownership.",
        "required": [
          "token",
          "address",
          "network",
          "nonce",
          "signature"
        ]
      },
      "WalletAuthIdentityEntity": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "someone@example.com",
            "description": "The proven email address."
          },
          "name": {
            "type": "object",
            "nullable": true,
            "description": "Display name from the identity provider; null when it gave none."
          },
          "avatar": {
            "type": "object",
            "nullable": true,
            "description": "Avatar image URL from the identity provider; null when it gave none."
          },
          "method": {
            "type": "string",
            "enum": [
              "authentik",
              "google",
              "github",
              "email"
            ],
            "description": "How the email was proven."
          }
        },
        "description": "The identity a wallet sign-in proved: the email address and how it was proven.",
        "required": [
          "email",
          "method"
        ]
      },
      "WalletBackupEntity": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "The chain of the backed-up account."
          },
          "address": {
            "type": "string",
            "description": "The account this box restores to, on `chain` (Stellar G…, Solana base58, Monad 0x…)."
          },
          "stellarAddress": {
            "type": "string",
            "description": "Same as `address` (the field’s original name, kept for older wallets).",
            "deprecated": true
          },
          "box": {
            "type": "string",
            "description": "The sealed box, verbatim. Opaque to this service: only the person's password or passkey opens it (a `v: 3` box carries one door per secret), and neither ever arrives here."
          },
          "updatedAt": {
            "type": "string",
            "description": "When the box was last written (ISO 8601)."
          }
        },
        "description": "One sealed wallet backup an account keeps: one box per chain and address.",
        "required": [
          "chain",
          "address",
          "stellarAddress",
          "box",
          "updatedAt"
        ]
      },
      "WalletAuthReadyEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ready"
            ],
            "description": "Always `ready`."
          },
          "identity": {
            "description": "The identity the sign-in proved.",
            "allOf": [
              {
                "$ref": "#/components/schemas/WalletAuthIdentityEntity"
              }
            ]
          },
          "account": {
            "type": "string",
            "enum": [
              "existing",
              "new"
            ],
            "description": "Whether this email already had an account here. A marker, never an id: it is what a client branches its onboarding on."
          },
          "backups": {
            "description": "Every wallet this account keeps a backup of, newest first: one box per (chain, address). A new device opens each with the password (or passkey) it was sealed under; a box sealed under another password stays closed.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WalletBackupEntity"
            }
          },
          "backup": {
            "nullable": true,
            "description": "The newest of `backups`, for wallets that read a single box.",
            "deprecated": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/WalletBackupEntity"
              }
            ]
          },
          "sessionToken": {
            "type": "string",
            "description": "Short-lived, sealed, and accepted by exactly one route: `/auth/finish`. It is the only credential that can create an account or put a backup under one, so it is never refreshed: a person who takes longer signs in again."
          },
          "expiresInSeconds": {
            "type": "number",
            "example": 1800,
            "description": "Lifetime of `sessionToken`, in seconds."
          },
          "idToken": {
            "type": "string",
            "description": "The OIDC provider's ID token, present ONLY when the sign-in went through Authentik AND the inbox was proven with an emailed code after it (a claim with `purpose: 'recovery'`, or an existing account). It is what the SEP-30 recovery servers accept as the person's identity, each verifying it against the provider's keys. Never stored by the wallet."
          }
        },
        "description": "A proven email: its identity, the backups its account keeps and the session token that finishes the sign-in.",
        "required": [
          "status",
          "identity",
          "account",
          "backups",
          "sessionToken",
          "expiresInSeconds"
        ]
      },
      "WalletAuthVerifyEmailEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "verify_email"
            ],
            "description": "Always `verify_email`."
          },
          "claimToken": {
            "type": "string",
            "description": "Send this back with the code."
          },
          "expiresInSeconds": {
            "type": "number",
            "example": 900,
            "description": "Lifetime of the emailed code, in seconds."
          },
          "email": {
            "type": "string",
            "description": "The mailbox the code went to."
          }
        },
        "description": "The email already has an account: a code was sent to its inbox, to be answered with `claimToken`.",
        "required": [
          "status",
          "claimToken",
          "expiresInSeconds",
          "email"
        ]
      },
      "WalletCodeInvalidEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "invalid"
            ],
            "description": "Always `invalid`."
          },
          "attemptsLeft": {
            "type": "number",
            "example": 4,
            "description": "Attempts left for this code."
          }
        },
        "description": "A wrong code, with how many attempts are left before the code stops being accepted.",
        "required": [
          "status",
          "attemptsLeft"
        ]
      },
      "WalletProvisionedKeysEntity": {
        "type": "object",
        "properties": {
          "dev": {
            "type": "object",
            "nullable": true,
            "description": "The account's `dev` (testnet) API key."
          },
          "prod": {
            "type": "object",
            "nullable": true,
            "description": "The account's `prod` (mainnet) API key."
          }
        },
        "description": "The gateway API keys of the signed-in account, one per environment."
      },
      "WalletSignInFinishedEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ready"
            ],
            "description": "Always `ready`."
          },
          "account": {
            "type": "string",
            "enum": [
              "created",
              "linked"
            ],
            "description": "Whether this call created the account or attached the identity to one that already existed. A different vocabulary from `ready.account`, deliberately: they answer two different questions."
          },
          "organizationId": {
            "type": "string",
            "description": "Id of the account's organization, carried by its API keys."
          },
          "keys": {
            "description": "The account's gateway API keys.",
            "allOf": [
              {
                "$ref": "#/components/schemas/WalletProvisionedKeysEntity"
              }
            ]
          }
        },
        "description": "A finished wallet sign-in: the account exists and holds its gateway API keys.",
        "required": [
          "status",
          "account",
          "organizationId",
          "keys"
        ]
      },
      "WalletAuthSourceEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "google",
            "description": "Send as `source` on /oauth/authorize."
          },
          "name": {
            "type": "string",
            "example": "Google",
            "description": "The button’s label: the provider’s own name."
          }
        },
        "description": "An Authentik source (e.g. Google, GitHub) a wallet can show as a sign-in button of its own.",
        "required": [
          "id",
          "name"
        ]
      },
      "WalletAuthProvidersEntity": {
        "type": "object",
        "properties": {
          "providers": {
            "example": [
              "authentik",
              "google",
              "github"
            ],
            "description": "Which providers this deployment has credentials for. Render buttons from this rather than from a compiled-in list, so a deployment that configured neither does not show two buttons that die at the consent screen.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "description": "Authentik’s own sources (Google, GitHub…), each to show as a button of its own that starts the Authentik sign-in at that source. With these, a wallet need not show a generic Authentik button. Empty without Authentik, or when the operator listed none (WALLET_AUTH_OIDC_SOURCES).",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WalletAuthSourceEntity"
            }
          },
          "email": {
            "type": "boolean",
            "description": "Whether the email-code door works here. False when no console is configured to deliver the mail."
          },
          "mfaSettingsUrl": {
            "type": "string",
            "nullable": true,
            "example": "https://auth.example.com/if/user/#/settings;{\"page\":\"page-credentials\"}",
            "description": "The page of the person’s Cosmos Pay (Authentik) account where they add or remove a second factor (a security key or passkey, an authenticator app, recovery codes), to open in a browser. It goes through the Authentik login first when there is no session. A second factor is optional (the sign-in only offers one), so offer this as a setting. Null when this deployment has no Authentik."
          }
        },
        "description": "The sign-in methods this deployment offers to the wallet.",
        "required": [
          "providers",
          "sources",
          "email",
          "mfaSettingsUrl"
        ]
      },
      "StartWalletOauthDto": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string",
            "enum": [
              "authentik",
              "google",
              "github"
            ],
            "example": "google",
            "description": "The identity provider to sign in with."
          },
          "codeChallenge": {
            "type": "string",
            "description": "base64url(SHA-256(verifier)), RFC 7636 S256. Keep the verifier on the device: it is what makes a `state` seen in a browser worthless to anyone else, and it is the only thing that can redeem this handshake.",
            "example": "E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM"
          },
          "codeChallengeMethod": {
            "type": "string",
            "enum": [
              "S256"
            ],
            "description": "RFC 7636 S256, the only method accepted. Declared rather than ignored: the wallet sends it, and an undeclared field is a 400 under `forbidNonWhitelisted`. Pinned rather than defaulted, because `plain` is the one value that would make the verifier no secret at all."
          },
          "returnTo": {
            "type": "string",
            "description": "A native wallet’s own URL: a custom scheme, a universal/app link, or `http://127.0.0.1:<port>/…` from a desktop app. When set, the callback answers `302` to it with `?state=…` (plus `&error=<reason>` on failure) instead of rendering a page, which is what closes the platform’s auth session. Must be listed in the deployment’s `WALLET_AUTH_RETURN_URLS` (a loopback entry matches any port). Only the `state` travels: the handshake is still redeemed with the verifier.",
            "example": "cosmoswallet://auth/done"
          },
          "source": {
            "type": "string",
            "description": "Start at one of Authentik’s sources (Google, GitHub…) instead of its login page: an `id` from `sources` on GET /v1/wallet/auth/providers, with `provider: authentik`. The browser goes straight to that provider and comes back through Authentik, so the handshake and its ID token are the same as any Authentik sign-in. Send it only to a deployment that listed it: an older one refuses the unknown field.",
            "example": "google"
          }
        },
        "description": "Starts an OAuth (PKCE) wallet sign-in with an identity provider.",
        "required": [
          "provider",
          "codeChallenge",
          "codeChallengeMethod"
        ]
      },
      "WalletOauthStartedEntity": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "description": "The handshake handle. Public by construction: it travels in a URL bar. Knowing it buys polling, never redemption."
          },
          "authorizationUrl": {
            "type": "string",
            "description": "Open this in a browser."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the handshake expires (ISO 8601)."
          }
        },
        "description": "A started OAuth sign-in handshake: the URL to open in a browser and the `state` handle to poll.",
        "required": [
          "state",
          "authorizationUrl",
          "expiresAt"
        ]
      },
      "WalletAuthStatusEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "authorized",
              "redeemed",
              "failed",
              "expired"
            ],
            "description": "Poll until this leaves `pending`. `authorized` means the person came back and the identity is waiting for the PKCE verifier. The identity itself is never in this response, at any status."
          },
          "error": {
            "type": "string",
            "enum": [
              "denied",
              "email_unverified",
              "profile_invalid",
              "failed"
            ],
            "description": "Present only on `failed`. A token to map to a sentence, never prose, which cannot be translated on the device."
          },
          "bound": {
            "type": "boolean",
            "description": "Present (true) only on `authorized`, after an Authentik emailed sign-in whose callback sent the wallet’s return URL a device binding: claim with it (`binding`), or the claim sends the inbox a code. The value itself is never in this response."
          }
        },
        "description": "The state of an OAuth sign-in handshake. The identity itself is never in this response.",
        "required": [
          "status"
        ]
      },
      "ClaimWalletOauthDto": {
        "type": "object",
        "properties": {
          "state": {
            "type": "string",
            "description": "The handshake handle, from /oauth/authorize."
          },
          "codeVerifier": {
            "type": "string",
            "description": "The PKCE verifier this device kept. Never sent anywhere else, and never stored by this service."
          },
          "purpose": {
            "type": "string",
            "enum": [
              "sign-in",
              "recovery"
            ],
            "default": "sign-in",
            "description": "`recovery` when the proven identity is going to be presented to the SEP-30 recovery servers. It always routes through an emailed code, even for an email with no account, and only then does the answer carry the provider's `idToken`: a provider proves who consented, not who opened the sign-in, and a recovery identity is worth a wallet. The one exception is an existing account signed in through Authentik’s emailed link (`cosmos_inbox_proven: true` in its ID token), which already proved the inbox."
          },
          "binding": {
            "type": "string",
            "description": "The device binding: the one-time value the callback put in the fragment of its redirect to the wallet’s return URL, after an Authentik emailed sign-in (the poll says `bound`). Only with it does that sign-in skip the code for an existing account. Send it only when the poll said `bound`: an older server refuses the unknown field."
          }
        },
        "description": "Redeems a finished OAuth sign-in handshake with its PKCE verifier.",
        "required": [
          "state",
          "codeVerifier"
        ]
      },
      "StartWalletEmailDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "someone@example.com",
            "description": "The email address to send the six-digit code to."
          }
        },
        "description": "Starts a wallet sign-in by emailed code.",
        "required": [
          "email"
        ]
      },
      "WalletEmailStartedEntity": {
        "type": "object",
        "properties": {
          "claimToken": {
            "type": "string",
            "description": "Identifies WHICH code is being answered, so a second request for the same mailbox cannot be answered with the first code. Only its SHA-256 is stored here."
          },
          "expiresInSeconds": {
            "type": "number",
            "example": 900,
            "description": "Lifetime of the emailed code, in seconds."
          }
        },
        "description": "An emailed sign-in code was sent; answer it with this `claimToken`.",
        "required": [
          "claimToken",
          "expiresInSeconds"
        ]
      },
      "VerifyWalletEmailDto": {
        "type": "object",
        "properties": {
          "claimToken": {
            "type": "string",
            "description": "The claim token returned by /auth/email/start."
          },
          "code": {
            "type": "string",
            "example": "048213",
            "description": "The six digits emailed."
          }
        },
        "description": "Answers an emailed sign-in code.",
        "required": [
          "claimToken",
          "code"
        ]
      },
      "FinishWalletSignInDto": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "Chain the account is on. Omit for Stellar. Solana signs the challenge with ed25519 over its UTF-8 bytes; Monad with EIP-191 `personal_sign`."
          },
          "address": {
            "type": "string",
            "description": "The account on `chain`: Stellar G…, Solana base58, Monad 0x…. Send this or `stellarAddress`, not both.",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
          },
          "stellarAddress": {
            "type": "string",
            "description": "The Stellar account (the field’s original name, still accepted for Stellar). New clients send `address`.",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
            "deprecated": true
          },
          "signedAt": {
            "type": "string",
            "example": "2026-01-02T03:04:05Z",
            "description": "When the challenge was signed: an ISO 8601 instant in UTC (`Z`), at most millisecond precision; it must be close to the server's clock."
          },
          "signature": {
            "type": "string",
            "description": "Signature over the sign-in challenge: base64 ed25519 on Stellar, base64 or base58 ed25519 on Solana, 0x-hex EIP-191 on Monad. The exact bytes are documented on the operation; a client that rebuilds them from prose is one field-order change away from producing signatures nothing accepts."
          },
          "backup": {
            "type": "string",
            "description": "The device's sealed seed box, to keep for the next device: one per (chain, address), up to 20 per account. Opaque here: it is sealed under a key derived from a password this service never sees."
          },
          "replaceBackup": {
            "type": "boolean",
            "description": "Accepted for older wallets and ignored. Backups are kept per wallet: a box for another address is added beside the ones the account keeps, and a box for the same wallet replaces its own. Nothing is ever discarded to make room.",
            "default": false
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "description": "The ledger the account's signers are read from (a recovered account's key signs for it on the ledger it was re-keyed on). Omit for the default."
          }
        },
        "description": "Finishes a wallet sign-in: the wallet's signature over the sign-in challenge, and optionally its backup. The session token travels in `X-Wallet-Session`.",
        "required": [
          "signedAt",
          "signature"
        ]
      },
      "ReplaceWalletBackupDto": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "default": "stellar",
            "description": "Chain the account is on. Omit for Stellar. Solana signs the challenge with ed25519 over its UTF-8 bytes; Monad with EIP-191 `personal_sign`."
          },
          "address": {
            "type": "string",
            "description": "The account on `chain`: Stellar G…, Solana base58, Monad 0x…. Send this or `stellarAddress`, not both.",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
          },
          "stellarAddress": {
            "type": "string",
            "description": "The Stellar account (the field’s original name, still accepted for Stellar). New clients send `address`.",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
            "deprecated": true
          },
          "box": {
            "type": "string",
            "description": "The re-sealed box. Opaque to this service."
          },
          "signedAt": {
            "type": "string",
            "example": "2026-01-02T03:04:05Z",
            "description": "When the challenge was signed: an ISO 8601 instant in UTC (`Z`), at most millisecond precision; it must be close to the server's clock."
          },
          "signature": {
            "type": "string",
            "description": "Signature over the backup challenge (encoded as for sign-in), which covers the box's SHA-256, so one signature stores exactly one box."
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "description": "The ledger the account's signers are read from (a recovered account's key signs for it on the ledger it was re-keyed on). Omit for the default."
          }
        },
        "description": "Replaces the sealed backup box of one of the account's wallets, signed by that wallet.",
        "required": [
          "box",
          "signedAt",
          "signature"
        ]
      },
      "WalletBackupUpdatedEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok"
            ],
            "description": "Always `ok`."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana",
              "monad"
            ],
            "example": "stellar",
            "description": "The chain of the account whose box was replaced."
          },
          "address": {
            "type": "string",
            "description": "The account whose box was replaced, on `chain` (Stellar G…, Solana base58, Monad 0x…)."
          },
          "stellarAddress": {
            "type": "string",
            "description": "Same as `address` (the field’s original name, kept for older wallets).",
            "deprecated": true
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the box was replaced (ISO 8601)."
          }
        },
        "description": "Confirmation that a wallet backup box was replaced.",
        "required": [
          "status",
          "chain",
          "address",
          "stellarAddress",
          "updatedAt"
        ]
      },
      "SponsorRecoverySetupDto": {
        "type": "object",
        "properties": {
          "stellarAddress": {
            "type": "string",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN",
            "description": "The Stellar account (G...) to set the recovery signers on."
          },
          "signers": {
            "description": "The two recovery servers' signers for this account, in role order.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "signedAt": {
            "type": "string",
            "example": "2026-01-02T03:04:05Z",
            "description": "When the challenge was signed: an ISO 8601 instant in UTC (`Z`), at most millisecond precision; it must be close to the server's clock."
          },
          "signature": {
            "type": "string",
            "description": "base64 ed25519 signature over the recovery-setup challenge."
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "description": "The ledger the account's signers are read from (a recovered account's key signs for it on the ledger it was re-keyed on). Omit for the default."
          }
        },
        "description": "Asks the operator to sponsor the reserve of an account's two recovery signers.",
        "required": [
          "stellarAddress",
          "signers",
          "signedAt",
          "signature"
        ]
      },
      "WalletRecoverySetupEntity": {
        "type": "object",
        "properties": {
          "transaction": {
            "type": "string",
            "description": "base64 XDR, signed by the sponsor and NOT by the account: the wallet adds its signature only after its own guard has decoded every operation."
          },
          "sponsor": {
            "type": "string",
            "description": "The account paying the two signer reserves."
          },
          "network_passphrase": {
            "type": "string",
            "description": "Passphrase of the Stellar network the transaction is for."
          }
        },
        "description": "The sponsored recovery setup transaction, signed by the sponsor, for the account to sign.",
        "required": [
          "transaction",
          "sponsor",
          "network_passphrase"
        ]
      },
      "Sep10TokenDto": {
        "type": "object",
        "properties": {
          "transaction": {
            "type": "string",
            "description": "The challenge, signed by the account."
          }
        },
        "description": "SEP-10: the signed challenge transaction, exchanged for a token of that account.",
        "required": [
          "transaction"
        ]
      },
      "RecoveryIdTokenDto": {
        "type": "object",
        "properties": {
          "id_token": {
            "type": "string",
            "description": "An OIDC ID token from the provider this server names as OIDC_ISSUER in its stellar.toml. Accepted once per server."
          }
        },
        "description": "Proves an inbox to this recovery server with an OIDC ID token.",
        "required": [
          "id_token"
        ]
      },
      "RecoveryEmailStartDto": {
        "type": "object",
        "properties": {
          "email": {
            "type": "string",
            "example": "person@example.com",
            "description": "The inbox to prove."
          }
        },
        "description": "Asks this recovery server to email a code that proves an inbox.",
        "required": [
          "email"
        ]
      },
      "RecoveryEmailVerifyDto": {
        "type": "object",
        "properties": {
          "claim_token": {
            "type": "string",
            "description": "The `claim_token` from `POST /v1/sep30/identity/email/start` (base64url)."
          },
          "code": {
            "type": "string",
            "example": "123456",
            "description": "The six digits emailed."
          }
        },
        "description": "Answers the code this recovery server emailed.",
        "required": [
          "claim_token",
          "code"
        ]
      },
      "AuthMethodDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "email"
            ],
            "description": "The kind of auth method; `email` is the only one accepted."
          },
          "value": {
            "type": "string",
            "example": "person@example.com",
            "description": "The email address that proves this identity."
          }
        },
        "description": "SEP-30: one way to prove an identity (an email address).",
        "required": [
          "type",
          "value"
        ]
      },
      "IdentityDto": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "sender",
              "receiver"
            ],
            "description": "The identity's role: `owner`, `sender` or `receiver`."
          },
          "auth_methods": {
            "description": "How this identity proves itself.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/AuthMethodDto"
            }
          }
        },
        "description": "SEP-30: one identity that may recover the account, with its role and auth methods.",
        "required": [
          "role",
          "auth_methods"
        ]
      },
      "Sep30IdentitiesDto": {
        "type": "object",
        "properties": {
          "identities": {
            "description": "The account's identities.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/IdentityDto"
            }
          }
        },
        "description": "SEP-30: the identities that may recover an account.",
        "required": [
          "identities"
        ]
      },
      "Sep30SignDto": {
        "type": "object",
        "properties": {
          "transaction": {
            "type": "string",
            "description": "The transaction to co-sign, base64 XDR."
          }
        },
        "description": "SEP-30: a transaction for this server to co-sign for a recovered account.",
        "required": [
          "transaction"
        ]
      },
      "RecoveryShareDto": {
        "type": "object",
        "properties": {
          "share": {
            "type": "string",
            "description": "This server's half of the backup's recovery key: 32 random-looking bytes, base64. Useless without the other server's half.",
            "example": "q83vEjRWeJCrze8SNFZ4kKvN7xI0VniQq83vEjRWeJA="
          },
          "email": {
            "type": "string",
            "description": "The inbox that may take the half back, proven to THIS server with its identity token.",
            "example": "person@example.com"
          }
        },
        "description": "This server's half of a wallet backup's recovery key, filed under the inbox that may take it back.",
        "required": [
          "share",
          "email"
        ]
      },
      "PluginConfigFieldEntity": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "string",
              "number",
              "boolean"
            ],
            "example": "string",
            "description": "The setting's JSON type."
          },
          "description": {
            "type": "string",
            "example": "API key for your account at the provider.",
            "description": "What the setting is for, as the plugin describes it."
          },
          "required": {
            "type": "boolean",
            "example": true,
            "description": "Whether an installation must set it."
          },
          "secret": {
            "type": "boolean",
            "example": true,
            "description": "Sealed at rest; never returned by any route."
          }
        },
        "description": "One setting a plugin declares, which an installation fills in through `config`.",
        "required": [
          "type",
          "description",
          "required",
          "secret"
        ]
      },
      "PluginInstallationEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clx9z8a1b0000abcd1234efgh",
            "description": "The installation id."
          },
          "pluginVersion": {
            "type": "string",
            "example": "1.0.0",
            "description": "The plugin version this consent was given to."
          },
          "grantedCapabilities": {
            "type": "array",
            "example": [
              "payment_intents:read"
            ],
            "description": "The capabilities granted at the last install.",
            "items": {
              "type": "string",
              "enum": [
                "customers:read",
                "customers:write",
                "products:read",
                "products:write",
                "payment_intents:read"
              ]
            }
          },
          "pendingCapabilities": {
            "type": "array",
            "example": [],
            "description": "Declared by the current plugin version and not granted yet. While non-empty, every action answers 409 plugin_not_installed: install again to consent.",
            "items": {
              "type": "string",
              "enum": [
                "customers:read",
                "customers:write",
                "products:read",
                "products:write",
                "payment_intents:read"
              ]
            }
          },
          "config": {
            "type": "object",
            "additionalProperties": true,
            "example": {},
            "description": "Non-secret settings."
          },
          "secretsSet": {
            "example": [],
            "description": "Names of the secret settings that hold a value. Values are never returned.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the plugin was first installed (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "description": "When the installation was last changed (ISO 8601 date-time)."
          }
        },
        "description": "The calling API key's installation of a plugin: what was consented to, and its settings. Secret values are never returned.",
        "required": [
          "id",
          "pluginVersion",
          "grantedCapabilities",
          "pendingCapabilities",
          "config",
          "secretsSet",
          "createdAt",
          "updatedAt"
        ]
      },
      "PluginEntity": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "example": "example",
            "description": "The plugin id: URL-safe, unique and permanent, as `/v1/plugins/{slug}` takes it."
          },
          "name": {
            "type": "string",
            "example": "Example: payment notes",
            "description": "The plugin's display name."
          },
          "version": {
            "type": "string",
            "example": "1.0.0",
            "description": "The plugin's current version (semver)."
          },
          "description": {
            "type": "string",
            "example": "Reference plugin: keeps a timeline of notes per payment intent, and adds one when it is paid.",
            "description": "What the plugin does, as its manifest describes it."
          },
          "author": {
            "type": "string",
            "example": "Cosmos Pay support",
            "description": "Who maintains the plugin: a person, a company or a repository URL."
          },
          "capabilities": {
            "type": "array",
            "example": [
              "payment_intents:read"
            ],
            "description": "What the plugin may do with the core. Installing grants exactly these.",
            "items": {
              "type": "string",
              "enum": [
                "customers:read",
                "customers:write",
                "products:read",
                "products:write",
                "payment_intents:read"
              ]
            }
          },
          "egress": {
            "example": [],
            "description": "The only hosts the plugin can reach over HTTPS.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "config": {
            "type": "object",
            "additionalProperties": {
              "$ref": "#/components/schemas/PluginConfigFieldEntity"
            },
            "example": {
              "label": {
                "type": "string",
                "description": "Optional prefix for every note, e.g. your team name.",
                "required": false,
                "secret": false
              }
            },
            "description": "The settings the plugin declares, by setting name."
          },
          "queries": {
            "example": [
              "get-notes"
            ],
            "description": "Read-only actions, run with `POST /v1/plugins/{slug}/queries/{action}`.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "commands": {
            "example": [
              "add-note"
            ],
            "description": "Actions that write, run with `POST /v1/plugins/{slug}/commands/{action}`.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "events": {
            "type": "array",
            "example": [
              "PAYMENT_INTENT_SUCCEEDED"
            ],
            "description": "The core events the plugin handles.",
            "items": {
              "type": "string",
              "enum": [
                "PAYMENT_INTENT_CREATED",
                "PAYMENT_INTENT_UPDATED",
                "PAYMENT_INTENT_SUCCEEDED",
                "PAYMENT_INTENT_FAILED",
                "PAYMENT_INTENT_CANCELLED",
                "PAYMENT_INTENT_DELETED"
              ]
            }
          },
          "installation": {
            "nullable": true,
            "description": "The calling API key's installation of the plugin; null when it is not installed.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/PluginInstallationEntity"
              }
            ]
          }
        },
        "description": "A plugin this deployment serves: its manifest, its actions and events, and the calling API key's installation of it.",
        "required": [
          "slug",
          "name",
          "version",
          "description",
          "author",
          "capabilities",
          "egress",
          "config",
          "queries",
          "commands",
          "events",
          "installation"
        ]
      },
      "PluginListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "Each plugin, with the calling API key's installation of it.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PluginEntity"
            }
          }
        },
        "description": "The plugins this deployment serves. Not paged.",
        "required": [
          "data"
        ]
      },
      "InstallPluginDto": {
        "type": "object",
        "properties": {
          "grantCapabilities": {
            "description": "Consent: exactly the capabilities the plugin declares (see GET /v1/plugins/{slug}). A partial or extra list is refused, so installing means having read it.",
            "example": [
              "payment_intents:read"
            ],
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "config": {
            "type": "object",
            "description": "Settings, as the plugin declares them. Secret fields are sealed at rest and never returned; leave one out on a re-install to keep the value already stored.",
            "additionalProperties": true,
            "example": {
              "label": "ops"
            }
          }
        },
        "description": "Request to install a plugin, or re-consent to or reconfigure it: consent to exactly its capabilities, and its settings.",
        "required": [
          "grantCapabilities"
        ]
      },
      "PluginUninstalledEntity": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string",
            "example": "example",
            "description": "The plugin uninstalled."
          },
          "uninstalled": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "The answer to an uninstall: the installation and every record the plugin kept for the API key are deleted.",
        "required": [
          "slug",
          "uninstalled"
        ]
      },
      "InvokePluginActionDto": {
        "type": "object",
        "properties": {
          "input": {
            "type": "object",
            "description": "The action input, as the plugin documents it. Plain JSON, at most 64 KiB.",
            "additionalProperties": true,
            "example": {
              "paymentIntentId": "clx9z8a1b0000abcd1234efgh",
              "text": "Customer called"
            }
          }
        },
        "description": "Request to run one of a plugin's queries or commands."
      },
      "PluginActionResultEntity": {
        "type": "object",
        "properties": {
          "plugin": {
            "type": "string",
            "example": "example",
            "description": "The slug of the plugin that ran the action."
          },
          "action": {
            "type": "string",
            "example": "get-notes",
            "description": "The action that ran."
          },
          "output": {
            "type": "object",
            "description": "Whatever the plugin returned, as JSON.",
            "example": {
              "paymentIntentId": "clx9z8a1b0000abcd1234efgh",
              "notes": [
                {
                  "at": "2026-09-29T12:00:00.000Z",
                  "text": "Customer called",
                  "source": "tenant"
                }
              ]
            }
          }
        },
        "description": "What a plugin query or command returned.",
        "required": [
          "plugin",
          "action",
          "output"
        ]
      },
      "ReceiverOwnerDto": {
        "type": "object",
        "properties": {
          "role": {
            "type": "string",
            "example": "beneficial_owner",
            "description": "The person's role in the business, as a BlindPay code (for example `beneficial_owner`)."
          },
          "first_name": {
            "type": "string",
            "example": "Jane",
            "description": "Owner's first name."
          },
          "last_name": {
            "type": "string",
            "example": "Doe",
            "description": "Owner's last name."
          },
          "date_of_birth": {
            "type": "string",
            "example": "1985-04-12T00:00:00.000Z",
            "format": "date-time",
            "description": "ISO 8601 date-time with an offset (BlindPay rejects date-only values)."
          },
          "tax_id": {
            "type": "string",
            "example": "123-45-6789",
            "description": "Owner's tax id."
          },
          "country": {
            "type": "string",
            "example": "US",
            "pattern": "^[A-Z]{2}$",
            "description": "ISO 3166-1 alpha-2 country code, upper case"
          },
          "address_line_1": {
            "type": "string",
            "example": "123 Main St",
            "description": "First line of the owner's address."
          },
          "address_line_2": {
            "type": "string",
            "description": "Second line of the owner's address."
          },
          "city": {
            "type": "string",
            "example": "New York",
            "description": "City of the owner's address."
          },
          "state_province_region": {
            "type": "string",
            "example": "NY",
            "description": "State, province or region of the owner's address."
          },
          "postal_code": {
            "type": "string",
            "example": "10001",
            "description": "Postal code of the owner's address."
          },
          "ownership_percentage": {
            "type": "number",
            "example": 25.5,
            "minimum": 0,
            "maximum": 100,
            "description": "Ownership percentage"
          },
          "title": {
            "type": "string",
            "example": "Director",
            "description": "Owner's title in the business (for example `Director`)."
          },
          "id_doc_country": {
            "type": "string",
            "example": "US",
            "pattern": "^[A-Z]{2}$",
            "description": "ISO 3166-1 alpha-2 country code, upper case"
          },
          "id_doc_type": {
            "type": "string",
            "example": "PASSPORT",
            "description": "Type of the owner's identity document (for example `PASSPORT`)."
          },
          "id_doc_front_file": {
            "type": "string",
            "description": "file_url from POST /v1/kyc/upload"
          },
          "id_doc_back_file": {
            "type": "string",
            "description": "Back of the owner's identity document: a `file_url` from `POST /v1/kyc/upload`."
          },
          "proof_of_address_doc_type": {
            "type": "string",
            "example": "UTILITY_BILL",
            "description": "Type of the owner's proof-of-address document (for example `UTILITY_BILL`)."
          },
          "proof_of_address_doc_file": {
            "type": "string",
            "description": "file_url from POST /v1/kyc/upload"
          },
          "tax_type": {
            "type": "string",
            "description": "Owner's tax id type."
          }
        },
        "description": "A beneficial owner or controlling person of a business (KYB) receiver, stored with it and sent to BlindPay when the receiver is enabled."
      },
      "CreateReceiverDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "individual",
              "business"
            ],
            "example": "individual",
            "description": "`individual` for a person (KYC) or `business` for a company (KYB)."
          },
          "kyc_type": {
            "type": "string",
            "enum": [
              "light",
              "standard",
              "enhanced"
            ],
            "example": "standard",
            "description": "Depth of compliance verification: `light`, `standard` or `enhanced`."
          },
          "email": {
            "type": "string",
            "example": "jane@acme.com",
            "description": "Receiver's email address, at most 160 characters."
          },
          "country": {
            "type": "string",
            "example": "US",
            "pattern": "^[A-Z]{2}$",
            "description": "ISO 3166-1 alpha-2 country code, upper case"
          },
          "first_name": {
            "type": "string",
            "example": "Jane",
            "description": "First name of an individual receiver; with `last_name` it forms the receiver `name`."
          },
          "last_name": {
            "type": "string",
            "example": "Doe",
            "description": "Last name of an individual receiver."
          },
          "date_of_birth": {
            "type": "string",
            "example": "1985-04-12T00:00:00.000Z",
            "format": "date-time",
            "description": "ISO 8601 date-time with an offset (BlindPay rejects date-only values)."
          },
          "tax_id": {
            "type": "string",
            "example": "123-45-6789",
            "description": "Receiver's tax id."
          },
          "occupation": {
            "type": "string",
            "example": "Engineer",
            "description": "Occupation of an individual receiver."
          },
          "id_doc_country": {
            "type": "string",
            "example": "US",
            "pattern": "^[A-Z]{2}$",
            "description": "ISO 3166-1 alpha-2 country code, upper case"
          },
          "id_doc_type": {
            "type": "string",
            "example": "PASSPORT",
            "description": "Type of the identity document (for example `PASSPORT`)."
          },
          "id_doc_front_file": {
            "type": "string",
            "description": "file_url from POST /v1/kyc/upload"
          },
          "id_doc_back_file": {
            "type": "string",
            "description": "Back of the identity document: a `file_url` from `POST /v1/kyc/upload`."
          },
          "selfie_file": {
            "type": "string",
            "description": "Selfie of the person: a `file_url` from `POST /v1/kyc/upload`."
          },
          "account_purpose": {
            "type": "string",
            "example": "receiving_payments",
            "description": "Purpose of the account, as a BlindPay code (for example `receiving_payments`)."
          },
          "account_purpose_other": {
            "type": "string",
            "description": "Free-text account purpose, forwarded to BlindPay with `account_purpose`."
          },
          "source_of_funds_doc_type": {
            "type": "string",
            "example": "employment",
            "description": "Type of the source-of-funds document, as a BlindPay code (for example `employment`)."
          },
          "source_of_funds_doc_file": {
            "type": "string",
            "description": "Source-of-funds document: a `file_url` from `POST /v1/kyc/upload`."
          },
          "source_of_wealth": {
            "type": "string",
            "description": "Source of the receiver's wealth, forwarded to BlindPay."
          },
          "sole_proprietor_doc_type": {
            "type": "string",
            "example": "bank_statement",
            "description": "master_service_agreement | salary_slip | bank_statement"
          },
          "proof_of_address_doc_type": {
            "type": "string",
            "example": "UTILITY_BILL",
            "description": "Type of the proof-of-address document (for example `UTILITY_BILL`)."
          },
          "proof_of_address_doc_file": {
            "type": "string",
            "description": "Proof-of-address document: a `file_url` from `POST /v1/kyc/upload`."
          },
          "recipient_relationship": {
            "type": "string",
            "example": "self",
            "description": "Relationship to the recipient, as a BlindPay code (for example `self`)."
          },
          "purpose_of_transactions": {
            "type": "string",
            "example": "business_transactions",
            "description": "Purpose of the receiver's transactions, as a BlindPay code (for example `business_transactions`); an enhanced KYC field."
          },
          "purpose_of_transactions_explanation": {
            "type": "string",
            "description": "Free-text explanation of `purpose_of_transactions`; an enhanced KYC field."
          },
          "legal_name": {
            "type": "string",
            "example": "Acme Inc.",
            "description": "Legal name of a business receiver; it becomes the receiver's `name`."
          },
          "alternate_name": {
            "type": "string",
            "example": "Acme",
            "description": "Alternate name of a business receiver."
          },
          "business_type": {
            "type": "string",
            "example": "cooperative",
            "description": "Type of business, as a BlindPay code (for example `cooperative`)."
          },
          "business_industry": {
            "type": "string",
            "example": "541511",
            "description": "Industry code of a business receiver, such as the NAICS code `541511`."
          },
          "business_description": {
            "type": "string",
            "description": "What a business receiver does."
          },
          "formation_date": {
            "type": "string",
            "example": "2015-01-01T00:00:00.000Z",
            "format": "date-time",
            "description": "ISO 8601 date-time with an offset (BlindPay rejects date-only values)."
          },
          "estimated_annual_revenue": {
            "type": "string",
            "example": "1000000_4999999",
            "description": "Estimated annual revenue band of a business receiver, as a BlindPay code (for example `1000000_4999999`)."
          },
          "publicly_traded": {
            "type": "boolean",
            "example": false,
            "description": "Whether a business receiver is publicly traded."
          },
          "website": {
            "type": "string",
            "example": "https://acme.com",
            "description": "Absolute http(s) URL, without credentials.",
            "maxLength": 2048
          },
          "incorporation_doc_file": {
            "type": "string",
            "description": "Incorporation document of a business receiver: a `file_url` from `POST /v1/kyc/upload`."
          },
          "proof_of_ownership_doc_file": {
            "type": "string",
            "description": "Proof-of-ownership document of a business receiver: a `file_url` from `POST /v1/kyc/upload`."
          },
          "owners": {
            "description": "Beneficial owners and controlling persons of a business receiver.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReceiverOwnerDto"
            }
          },
          "address_line_1": {
            "type": "string",
            "example": "123 Main St",
            "description": "First line of the receiver's address."
          },
          "address_line_2": {
            "type": "string",
            "description": "Second line of the receiver's address."
          },
          "city": {
            "type": "string",
            "example": "New York",
            "description": "City of the receiver's address."
          },
          "state_province_region": {
            "type": "string",
            "example": "NY",
            "description": "State, province or region of the receiver's address."
          },
          "postal_code": {
            "type": "string",
            "example": "10001",
            "description": "Postal code of the receiver's address."
          },
          "phone_number": {
            "type": "string",
            "example": "+12025550123",
            "description": "Receiver's phone number with its country code."
          },
          "ip_address": {
            "type": "string",
            "description": "Receiver's IP address, forwarded to BlindPay."
          },
          "external_id": {
            "type": "string",
            "description": "Your own id for this receiver"
          },
          "image_url": {
            "type": "string",
            "description": "URL of a display image for the receiver. With `external_id`, the only field a non-admin key may change once the receiver exists at BlindPay."
          },
          "tos_id": {
            "type": "string",
            "description": "Accepted terms-of-service id (from the redirect of POST /v1/kyc/terms-of-service). Required by BlindPay to create a receiver."
          }
        },
        "description": "A receiver, the person (KYC) or business (KYB) behind onramp and offramp: stored here and created at BlindPay only on enable. With KYC data (`tax_id`, `date_of_birth`, `id_doc_front_file`, `selfie_file`, `legal_name`, `formation_date` or `owners`) it starts in `pending_review`, otherwise in `inactive`.",
        "required": [
          "type",
          "kyc_type",
          "email",
          "country"
        ]
      },
      "ReceiverEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xreceiver01",
            "description": "Cosmos Pay id of the receiver, the `{id}` or `{receiverId}` of the receiver routes."
          },
          "blindpayId": {
            "type": "string",
            "example": "re_000000000000",
            "description": "BlindPay's receiver id (`re_...`); a `local_` placeholder until the receiver is enabled."
          },
          "type": {
            "type": "string",
            "example": "individual",
            "description": "`individual` (KYC) or `business` (KYB)."
          },
          "kycType": {
            "type": "object",
            "example": "standard",
            "description": "Depth of compliance verification: `light`, `standard` or `enhanced`."
          },
          "kycStatus": {
            "type": "object",
            "example": "verifying",
            "description": "BlindPay KYC status (verifying, approved, rejected, ...)."
          },
          "email": {
            "type": "object",
            "example": "jane@acme.com",
            "description": "Receiver's email address."
          },
          "name": {
            "type": "object",
            "example": "Jane Doe",
            "description": "Display name: a business's legal name, otherwise the person's first and last name."
          },
          "country": {
            "type": "object",
            "example": "US",
            "description": "Receiver's country, an ISO 3166-1 alpha-2 code."
          },
          "externalId": {
            "type": "object",
            "example": "cust_001",
            "description": "Your own id for the receiver (`external_id`)."
          },
          "disabled": {
            "type": "boolean",
            "example": false,
            "description": "Owner/admin kill-switch: when true the account is blocked from onramp/offramp."
          },
          "dossierVersion": {
            "type": "number",
            "example": 3,
            "description": "Version of the submitted KYC data. Bumped on every edit while the receiver is still local. Send it back as `expected_version` when approving, so the approval is pinned to the dossier that was reviewed."
          },
          "reviewedVersion": {
            "type": "number",
            "nullable": true,
            "example": 3,
            "description": "The `dossierVersion` an elevated reviewer approved, or null if the receiver has not been approved. Enabling is refused unless it equals `dossierVersion`."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-28T12:00:00.000Z",
            "description": "When the receiver was created here (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-28T12:00:00.000Z",
            "description": "When the receiver was last changed here (ISO 8601 date-time)."
          }
        },
        "description": "A receiver as this service mirrors it; the submitted KYC dossier is never returned.",
        "required": [
          "id",
          "blindpayId",
          "type",
          "disabled",
          "dossierVersion",
          "createdAt",
          "updatedAt"
        ]
      },
      "ReceiverListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The receivers on this page.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReceiverEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Matching rows, not the page length.",
            "example": 1
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "The page size applied, from the `take` query parameter (default 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Rows skipped before this page, from the `skip` query parameter (default 0)."
          }
        },
        "description": "One page of the consumer's receivers, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "ApproveReceiverDto": {
        "type": "object",
        "properties": {
          "redirect_url": {
            "type": "string",
            "example": "https://dev.cosmospay.lat/kyc/return/org/dev/clz9xreceiver01",
            "description": "Where BlindPay redirects the customer after they accept the terms. Must be https and on the consumer allow-list."
          },
          "expected_version": {
            "type": "number",
            "example": 3,
            "description": "The receiver's `dossierVersion` as you read it. A 409 `kyc_state_invalid` if the KYC data changed since: re-read, review again, approve that version. Omitted approves whatever is stored now."
          }
        },
        "description": "Approval of a `pending_review` receiver: requests its terms-of-service link and moves it to `pending_user`.",
        "required": [
          "redirect_url"
        ]
      },
      "ReceiverApprovalEntity": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "The hosted terms-of-service link. This service emails nothing: deliver it to the customer.",
            "example": "https://app.blindpay.com/e/terms-of-service?session_token=tos_example"
          },
          "email": {
            "type": "string",
            "description": "The receiver's email address, to deliver the link to, or null when the receiver has none.",
            "example": "customer@example.com",
            "nullable": true
          }
        },
        "description": "The terms-of-service link an approval requested, for the caller to deliver to the customer.",
        "required": [
          "url",
          "email"
        ]
      },
      "RequestTosDto": {
        "type": "object",
        "properties": {
          "channel": {
            "type": "string",
            "enum": [
              "code",
              "email"
            ],
            "default": "code",
            "description": "'code' returns the hosted ToS URL to display. 'email' records an email send, allowed once per 24 hours per receiver; it sends nothing itself, so you email the returned link."
          },
          "redirect_url": {
            "type": "string",
            "example": "https://yourapp.com/kyc/return",
            "description": "Where BlindPay redirects after acceptance (gets ?tos_id=...). Must be https and on the consumer allow-list."
          }
        },
        "description": "A request for a fresh terms-of-service link for a `pending_user` receiver.",
        "required": [
          "redirect_url"
        ]
      },
      "ReceiverTosEntity": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "The hosted terms-of-service link. This service emails nothing: deliver it to the customer.",
            "example": "https://app.blindpay.com/e/terms-of-service?session_token=tos_example"
          },
          "email": {
            "type": "string",
            "description": "The receiver's email address, to deliver the link to, or null when the receiver has none.",
            "example": "customer@example.com",
            "nullable": true
          },
          "channel": {
            "type": "string",
            "description": "`code`: the link to show yourself. `email`: the send was recorded (once per 24 hours per receiver); you email the link.",
            "enum": [
              "code",
              "email"
            ],
            "example": "code"
          }
        },
        "description": "A terms-of-service link for a `pending_user` receiver, and the channel it was requested for.",
        "required": [
          "url",
          "email",
          "channel"
        ]
      },
      "EnableReceiverDto": {
        "type": "object",
        "properties": {
          "tos_id": {
            "type": "string",
            "example": "to_a1b2c3d4e5f6g7h",
            "description": "Accepted terms-of-service id (the ?tos_id=... from the ToS redirect)."
          }
        },
        "description": "The accepted terms-of-service id that creates an approved (`pending_user`) receiver at BlindPay.",
        "required": [
          "tos_id"
        ]
      },
      "SetAccessDto": {
        "type": "object",
        "properties": {
          "disabled": {
            "type": "boolean",
            "example": true,
            "description": "true = disable the fiat account, false = enable."
          }
        },
        "description": "The receiver's fiat-access kill-switch for onramp and offramp, independent of its KYC status.",
        "required": [
          "disabled"
        ]
      },
      "UpdateReceiverDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "individual",
              "business"
            ],
            "example": "individual",
            "description": "`individual` for a person (KYC) or `business` for a company (KYB)."
          },
          "kyc_type": {
            "type": "string",
            "enum": [
              "light",
              "standard",
              "enhanced"
            ],
            "example": "standard",
            "description": "Depth of compliance verification: `light`, `standard` or `enhanced`."
          },
          "email": {
            "type": "string",
            "example": "jane@acme.com",
            "description": "Receiver's email address, at most 160 characters."
          },
          "country": {
            "type": "string",
            "example": "US",
            "pattern": "^[A-Z]{2}$",
            "description": "ISO 3166-1 alpha-2 country code, upper case"
          },
          "first_name": {
            "type": "string",
            "example": "Jane",
            "description": "First name of an individual receiver; with `last_name` it forms the receiver `name`."
          },
          "last_name": {
            "type": "string",
            "example": "Doe",
            "description": "Last name of an individual receiver."
          },
          "date_of_birth": {
            "type": "string",
            "example": "1985-04-12T00:00:00.000Z",
            "format": "date-time",
            "description": "ISO 8601 date-time with an offset (BlindPay rejects date-only values)."
          },
          "tax_id": {
            "type": "string",
            "example": "123-45-6789",
            "description": "Receiver's tax id."
          },
          "occupation": {
            "type": "string",
            "example": "Engineer",
            "description": "Occupation of an individual receiver."
          },
          "id_doc_country": {
            "type": "string",
            "example": "US",
            "pattern": "^[A-Z]{2}$",
            "description": "ISO 3166-1 alpha-2 country code, upper case"
          },
          "id_doc_type": {
            "type": "string",
            "example": "PASSPORT",
            "description": "Type of the identity document (for example `PASSPORT`)."
          },
          "id_doc_front_file": {
            "type": "string",
            "description": "file_url from POST /v1/kyc/upload"
          },
          "id_doc_back_file": {
            "type": "string",
            "description": "Back of the identity document: a `file_url` from `POST /v1/kyc/upload`."
          },
          "selfie_file": {
            "type": "string",
            "description": "Selfie of the person: a `file_url` from `POST /v1/kyc/upload`."
          },
          "account_purpose": {
            "type": "string",
            "example": "receiving_payments",
            "description": "Purpose of the account, as a BlindPay code (for example `receiving_payments`)."
          },
          "account_purpose_other": {
            "type": "string",
            "description": "Free-text account purpose, forwarded to BlindPay with `account_purpose`."
          },
          "source_of_funds_doc_type": {
            "type": "string",
            "example": "employment",
            "description": "Type of the source-of-funds document, as a BlindPay code (for example `employment`)."
          },
          "source_of_funds_doc_file": {
            "type": "string",
            "description": "Source-of-funds document: a `file_url` from `POST /v1/kyc/upload`."
          },
          "source_of_wealth": {
            "type": "string",
            "description": "Source of the receiver's wealth, forwarded to BlindPay."
          },
          "sole_proprietor_doc_type": {
            "type": "string",
            "example": "bank_statement",
            "description": "master_service_agreement | salary_slip | bank_statement"
          },
          "proof_of_address_doc_type": {
            "type": "string",
            "example": "UTILITY_BILL",
            "description": "Type of the proof-of-address document (for example `UTILITY_BILL`)."
          },
          "proof_of_address_doc_file": {
            "type": "string",
            "description": "Proof-of-address document: a `file_url` from `POST /v1/kyc/upload`."
          },
          "recipient_relationship": {
            "type": "string",
            "example": "self",
            "description": "Relationship to the recipient, as a BlindPay code (for example `self`)."
          },
          "purpose_of_transactions": {
            "type": "string",
            "example": "business_transactions",
            "description": "Purpose of the receiver's transactions, as a BlindPay code (for example `business_transactions`); an enhanced KYC field."
          },
          "purpose_of_transactions_explanation": {
            "type": "string",
            "description": "Free-text explanation of `purpose_of_transactions`; an enhanced KYC field."
          },
          "legal_name": {
            "type": "string",
            "example": "Acme Inc.",
            "description": "Legal name of a business receiver; it becomes the receiver's `name`."
          },
          "alternate_name": {
            "type": "string",
            "example": "Acme",
            "description": "Alternate name of a business receiver."
          },
          "business_type": {
            "type": "string",
            "example": "cooperative",
            "description": "Type of business, as a BlindPay code (for example `cooperative`)."
          },
          "business_industry": {
            "type": "string",
            "example": "541511",
            "description": "Industry code of a business receiver, such as the NAICS code `541511`."
          },
          "business_description": {
            "type": "string",
            "description": "What a business receiver does."
          },
          "formation_date": {
            "type": "string",
            "example": "2015-01-01T00:00:00.000Z",
            "format": "date-time",
            "description": "ISO 8601 date-time with an offset (BlindPay rejects date-only values)."
          },
          "estimated_annual_revenue": {
            "type": "string",
            "example": "1000000_4999999",
            "description": "Estimated annual revenue band of a business receiver, as a BlindPay code (for example `1000000_4999999`)."
          },
          "publicly_traded": {
            "type": "boolean",
            "example": false,
            "description": "Whether a business receiver is publicly traded."
          },
          "website": {
            "type": "string",
            "example": "https://acme.com",
            "description": "Absolute http(s) URL, without credentials.",
            "maxLength": 2048
          },
          "incorporation_doc_file": {
            "type": "string",
            "description": "Incorporation document of a business receiver: a `file_url` from `POST /v1/kyc/upload`."
          },
          "proof_of_ownership_doc_file": {
            "type": "string",
            "description": "Proof-of-ownership document of a business receiver: a `file_url` from `POST /v1/kyc/upload`."
          },
          "owners": {
            "description": "Beneficial owners and controlling persons of a business receiver.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ReceiverOwnerDto"
            }
          },
          "address_line_1": {
            "type": "string",
            "example": "123 Main St",
            "description": "First line of the receiver's address."
          },
          "address_line_2": {
            "type": "string",
            "description": "Second line of the receiver's address."
          },
          "city": {
            "type": "string",
            "example": "New York",
            "description": "City of the receiver's address."
          },
          "state_province_region": {
            "type": "string",
            "example": "NY",
            "description": "State, province or region of the receiver's address."
          },
          "postal_code": {
            "type": "string",
            "example": "10001",
            "description": "Postal code of the receiver's address."
          },
          "phone_number": {
            "type": "string",
            "example": "+12025550123",
            "description": "Receiver's phone number with its country code."
          },
          "ip_address": {
            "type": "string",
            "description": "Receiver's IP address, forwarded to BlindPay."
          },
          "external_id": {
            "type": "string",
            "description": "Your own id for this receiver"
          },
          "image_url": {
            "type": "string",
            "description": "URL of a display image for the receiver. With `external_id`, the only field a non-admin key may change once the receiver exists at BlindPay."
          },
          "tos_id": {
            "type": "string",
            "description": "Accepted terms-of-service id (from the redirect of POST /v1/kyc/terms-of-service). Required by BlindPay to create a receiver."
          }
        },
        "description": "Changes to a receiver: any field of the create body, all optional. `tos_id` is ignored, and once the receiver exists at BlindPay a non-admin key may change only `external_id` and `image_url`."
      },
      "ReceiverDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xreceiver01",
            "description": "The receiver id from the request path."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirms a receiver deletion.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "CreateWalletDto": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "example": "Primary wallet",
            "description": "A label for the wallet, forwarded to BlindPay."
          },
          "network": {
            "type": "string",
            "enum": [
              "ethereum",
              "base",
              "arbitrum",
              "polygon",
              "stellar",
              "solana",
              "tron",
              "sepolia",
              "base_sepolia",
              "arbitrum_sepolia",
              "polygon_amoy",
              "stellar_testnet",
              "solana_devnet"
            ],
            "example": "stellar",
            "description": "BlindPay network the wallet is on (mainnets and their test networks)."
          },
          "address": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "Wallet address (account-abstraction / non-secure flow)."
          },
          "signature_tx_hash": {
            "type": "string",
            "description": "Signed sign-message tx hash (secure EOA flow)."
          },
          "is_account_abstraction": {
            "type": "boolean",
            "example": true,
            "description": "Whether `address` is an account-abstraction wallet."
          }
        },
        "description": "A blockchain wallet to register for a receiver: send `address`, or the `signature_tx_hash` of the signed sign-message (secure EOA flow).",
        "required": [
          "name",
          "network"
        ]
      },
      "WalletEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xwallet001",
            "description": "Cosmos Pay id of the wallet; pass it as `blockchain_wallet_id` to onramp quotes and virtual accounts."
          },
          "blindpayId": {
            "type": "string",
            "example": "bw_000000000000",
            "description": "BlindPay's wallet id (`bw_...`)."
          },
          "name": {
            "type": "object",
            "example": "Primary wallet",
            "description": "Label of the wallet."
          },
          "network": {
            "type": "string",
            "example": "stellar",
            "description": "BlindPay network the wallet is on (for example `stellar`)."
          },
          "address": {
            "type": "object",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "Wallet address on `network`."
          },
          "isAccountAbstraction": {
            "type": "boolean",
            "example": false,
            "description": "Whether the wallet is an account-abstraction wallet."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-28T12:00:00.000Z",
            "description": "When this service recorded the wallet (ISO 8601 date-time)."
          }
        },
        "description": "A receiver's blockchain wallet as this service mirrors it.",
        "required": [
          "id",
          "blindpayId",
          "network",
          "isAccountAbstraction",
          "createdAt"
        ]
      },
      "WalletListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The wallets on this page.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WalletEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Matching rows, not the page length.",
            "example": 1
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "The page size applied, from the `take` query parameter (default 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Rows skipped before this page, from the `skip` query parameter (default 0)."
          }
        },
        "description": "One page of a receiver's wallets, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "WalletDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xwallet001",
            "description": "The wallet id from the request path."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirms a wallet deletion; an id the receiver does not have gets the same answer, so repeating a delete succeeds.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "CreateBankAccountDto": {
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "wire",
              "ach",
              "rtp",
              "pix",
              "pix_safe",
              "ted",
              "spei_bitso",
              "transfers_bitso",
              "ach_cop_bitso",
              "international_swift",
              "sepa"
            ],
            "example": "ach",
            "description": "The rail the account settles on; it decides which of the rail-specific fields apply."
          },
          "name": {
            "type": "string",
            "example": "Acme payouts (USD)",
            "description": "A label for the account, forwarded to BlindPay."
          },
          "account_class": {
            "type": "string",
            "enum": [
              "individual",
              "business"
            ],
            "example": "individual",
            "description": "Ownership class of the account (`individual` or `business`), used by the US and EUR rails."
          },
          "account_type": {
            "type": "string",
            "enum": [
              "checking",
              "saving"
            ],
            "example": "checking",
            "description": "Checking or savings account, for the rails that distinguish them."
          },
          "beneficiary_name": {
            "type": "string",
            "example": "Jane Doe",
            "description": "Name of the account's beneficiary."
          },
          "recipient_relationship": {
            "type": "string",
            "example": "first_party",
            "description": "Relationship to the recipient, as a BlindPay code (for example `first_party`)."
          },
          "account_number": {
            "type": "string",
            "example": "0123456789",
            "description": "Bank account number (`ach`, `wire` and `rtp` rails, United States)."
          },
          "routing_number": {
            "type": "string",
            "example": "021000021",
            "description": "Bank routing number (`ach`, `wire` and `rtp` rails, United States)."
          },
          "business_industry": {
            "type": "string",
            "example": "541511",
            "description": "NAICS code; required for business-class US/SWIFT accounts."
          },
          "phone_number": {
            "type": "string",
            "example": "+12025550123",
            "description": "Phone number with its country code; a compliance field the ACH, Wire, RTP and SWIFT rails may require."
          },
          "tax_id": {
            "type": "string",
            "example": "123456789",
            "description": "Tax id; a compliance field the ACH, Wire, RTP and SWIFT rails may require."
          },
          "pix_key": {
            "type": "string",
            "example": "jane@acme.com",
            "description": "PIX key of the destination account, such as an email address (`pix` rail, Brazil)."
          },
          "pix_safe_bank_code": {
            "type": "string",
            "description": "Bank code of the destination account (`pix_safe` rail, Brazil)."
          },
          "pix_safe_branch_code": {
            "type": "string",
            "description": "Branch code of the destination account (`pix_safe` rail, Brazil)."
          },
          "pix_safe_cpf_cnpj": {
            "type": "string",
            "description": "CPF or CNPJ (Brazilian tax id) of the account holder (`pix_safe` rail, Brazil)."
          },
          "ted_bank_code": {
            "type": "string",
            "description": "Bank code of the destination account (`ted` rail, Brazil)."
          },
          "ted_branch_code": {
            "type": "string",
            "description": "Branch code of the destination account (`ted` rail, Brazil)."
          },
          "ted_cpf_cnpj": {
            "type": "string",
            "description": "CPF or CNPJ (Brazilian tax id) of the account holder (`ted` rail, Brazil)."
          },
          "transfers_account": {
            "type": "string",
            "example": "0000003100010000000001",
            "description": "Destination CVU, CBU or alias (`transfers_bitso` rail, Argentina); say which in `transfers_type`."
          },
          "transfers_type": {
            "type": "string",
            "example": "CBU",
            "description": "CVU | CBU | ALIAS"
          },
          "spei_clabe": {
            "type": "string",
            "example": "012345678901234567",
            "description": "CLABE of the destination account (`spei_bitso` rail, Mexico)."
          },
          "spei_institution_code": {
            "type": "string",
            "description": "Institution code of the destination bank (`spei_bitso` rail, Mexico)."
          },
          "spei_protocol": {
            "type": "string",
            "description": "SPEI protocol value, forwarded to BlindPay (`spei_bitso` rail, Mexico)."
          },
          "ach_cop_beneficiary_first_name": {
            "type": "string",
            "description": "Beneficiary first name (`ach_cop_bitso` rail, Colombia)."
          },
          "ach_cop_beneficiary_last_name": {
            "type": "string",
            "description": "Beneficiary last name (`ach_cop_bitso` rail, Colombia)."
          },
          "ach_cop_document_id": {
            "type": "string",
            "description": "Number of the beneficiary's identity document (`ach_cop_bitso` rail, Colombia)."
          },
          "ach_cop_document_type": {
            "type": "string",
            "description": "Type of the beneficiary's identity document (`ach_cop_bitso` rail, Colombia)."
          },
          "ach_cop_email": {
            "type": "string",
            "description": "Beneficiary email address (`ach_cop_bitso` rail, Colombia)."
          },
          "ach_cop_bank_code": {
            "type": "string",
            "description": "Code of the destination bank (`ach_cop_bitso` rail, Colombia)."
          },
          "ach_cop_bank_account": {
            "type": "string",
            "description": "Destination bank account number (`ach_cop_bitso` rail, Colombia)."
          },
          "swift_account_holder_name": {
            "type": "string",
            "description": "Name of the account holder (`international_swift` rail)."
          },
          "swift_account_number_iban": {
            "type": "string",
            "description": "Account number or IBAN of the destination account (`international_swift` rail)."
          },
          "swift_code_bic": {
            "type": "string",
            "description": "SWIFT/BIC code of the destination bank (`international_swift` rail)."
          },
          "swift_bank_name": {
            "type": "string",
            "description": "Name of the destination bank (`international_swift` rail)."
          },
          "swift_bank_address_line_1": {
            "type": "string",
            "description": "First line of the destination bank's address (`international_swift` rail)."
          },
          "swift_bank_city": {
            "type": "string",
            "description": "City of the destination bank (`international_swift` rail)."
          },
          "swift_bank_state_province_region": {
            "type": "string",
            "description": "State, province or region of the destination bank (`international_swift` rail)."
          },
          "swift_bank_country": {
            "type": "string",
            "description": "Country of the destination bank (`international_swift` rail)."
          },
          "swift_bank_postal_code": {
            "type": "string",
            "description": "Postal code of the destination bank (`international_swift` rail)."
          },
          "swift_beneficiary_address_line_1": {
            "type": "string",
            "description": "First line of the beneficiary's address (`international_swift` rail)."
          },
          "swift_beneficiary_city": {
            "type": "string",
            "description": "City of the beneficiary's address (`international_swift` rail)."
          },
          "swift_beneficiary_state_province_region": {
            "type": "string",
            "description": "State, province or region of the beneficiary's address (`international_swift` rail)."
          },
          "swift_beneficiary_country": {
            "type": "string",
            "description": "Country of the beneficiary's address (`international_swift` rail)."
          },
          "swift_beneficiary_postal_code": {
            "type": "string",
            "description": "Postal code of the beneficiary's address (`international_swift` rail)."
          },
          "swift_bank_address_line_2": {
            "type": "string",
            "description": "Second line of the destination bank's address (`international_swift` rail)."
          },
          "swift_beneficiary_address_line_2": {
            "type": "string",
            "description": "Second line of the beneficiary's address (`international_swift` rail)."
          },
          "swift_payment_code": {
            "type": "string",
            "description": "SWIFT payment/purpose code."
          },
          "swift_intermediary_bank_swift_code_bic": {
            "type": "string",
            "description": "SWIFT/BIC code of the intermediary bank, when the transfer goes through one (`international_swift` rail)."
          },
          "swift_intermediary_bank_account_number_iban": {
            "type": "string",
            "description": "Account number or IBAN at the intermediary bank (`international_swift` rail)."
          },
          "swift_intermediary_bank_name": {
            "type": "string",
            "description": "Name of the intermediary bank (`international_swift` rail)."
          },
          "swift_intermediary_bank_country": {
            "type": "string",
            "description": "Country of the intermediary bank (`international_swift` rail)."
          },
          "sepa_iban": {
            "type": "string",
            "description": "IBAN of the destination account (`sepa` rail, EUR)."
          },
          "sepa_beneficiary_bic": {
            "type": "string",
            "description": "BIC of the beneficiary's bank (`sepa` rail)."
          },
          "sepa_beneficiary_legal_name": {
            "type": "string",
            "description": "Legal name of the beneficiary (`sepa` rail)."
          },
          "sepa_beneficiary_address_line_1": {
            "type": "string",
            "description": "First line of the beneficiary's address (`sepa` rail)."
          },
          "sepa_beneficiary_city": {
            "type": "string",
            "description": "City of the beneficiary's address (`sepa` rail)."
          },
          "sepa_beneficiary_postal_code": {
            "type": "string",
            "description": "Postal code of the beneficiary's address (`sepa` rail)."
          },
          "sepa_beneficiary_country": {
            "type": "string",
            "description": "Country of the beneficiary's address (`sepa` rail)."
          },
          "sepa_beneficiary_address_line_2": {
            "type": "string",
            "description": "Second line of the beneficiary's address (`sepa` rail)."
          },
          "sepa_beneficiary_state_province_region": {
            "type": "string",
            "description": "State, province or region of the beneficiary's address (`sepa` rail)."
          },
          "address_line_1": {
            "type": "string",
            "description": "First line of the beneficiary's address, for the US, SWIFT and SEPA rails."
          },
          "address_line_2": {
            "type": "string",
            "description": "Second line of the beneficiary's address, for the US, SWIFT and SEPA rails."
          },
          "city": {
            "type": "string",
            "description": "City of the beneficiary's address, for the US, SWIFT and SEPA rails."
          },
          "state_province_region": {
            "type": "string",
            "description": "State, province or region of the beneficiary's address, for the US, SWIFT and SEPA rails."
          },
          "country": {
            "type": "string",
            "description": "Country of the beneficiary's address, for the US, SWIFT and SEPA rails."
          },
          "postal_code": {
            "type": "string",
            "description": "Postal code of the beneficiary's address, for the US, SWIFT and SEPA rails."
          }
        },
        "description": "A fiat bank account to add to a receiver, where its offramp payouts settle. `type` names the rail and only that rail's fields are needed (`GET /v1/kyc/bank-details?rail=` lists them); the body is forwarded to BlindPay.",
        "required": [
          "type",
          "name"
        ]
      },
      "BankAccountEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xbank00001",
            "description": "Cosmos Pay id of the bank account; pass it as `bank_account_id` to `POST /v1/offramp/quotes`."
          },
          "blindpayId": {
            "type": "string",
            "example": "ba_000000000000",
            "description": "BlindPay's id for the bank account (`ba_...`)."
          },
          "rail": {
            "type": "object",
            "example": "ach",
            "description": "Rail the account settles on: its BlindPay `type`, such as `ach`."
          },
          "name": {
            "type": "object",
            "example": "Acme payouts (USD)",
            "description": "Label of the account, as BlindPay returned it."
          },
          "country": {
            "type": "object",
            "example": "US",
            "description": "Country of the account, as BlindPay returned it."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-28T12:00:00.000Z",
            "description": "When this service recorded the account (ISO 8601 date-time)."
          }
        },
        "description": "A receiver's fiat bank account as this service mirrors it: identifiers only, never the account numbers.",
        "required": [
          "id",
          "blindpayId",
          "createdAt"
        ]
      },
      "BankAccountListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The bank accounts on this page.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BankAccountEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Matching rows, not the page length.",
            "example": 1
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "The page size applied, from the `take` query parameter (default 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Rows skipped before this page, from the `skip` query parameter (default 0)."
          }
        },
        "description": "One page of a receiver's bank accounts, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "BankAccountDeletedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xbank00001",
            "description": "The bank account id from the request path."
          },
          "deleted": {
            "type": "boolean",
            "example": true,
            "description": "Always true."
          }
        },
        "description": "Confirms a bank account deletion; an id the receiver does not have gets the same answer, so repeating a delete succeeds.",
        "required": [
          "id",
          "deleted"
        ]
      },
      "KycUploadEntity": {
        "type": "object",
        "properties": {
          "file_url": {
            "type": "string",
            "description": "The provider's URL for the file. Pass it as a document field when creating or updating a receiver.",
            "example": "https://files.blindpay.com/uploads/onboarding/doc_example.pdf"
          }
        },
        "description": "A KYC document stored at BlindPay, referenced by its URL in a receiver's `*_file` fields.",
        "required": [
          "file_url"
        ]
      },
      "InitiateTosDto": {
        "type": "object",
        "properties": {
          "redirect_url": {
            "type": "string",
            "example": "https://yourapp.com/kyc/return",
            "description": "Where BlindPay redirects after acceptance (gets ?tos_id=...). Must be https and on the consumer allow-list."
          },
          "receiver_id": {
            "type": "string",
            "description": "Existing receiver to (re)accept updated terms for."
          },
          "idempotency_key": {
            "type": "string",
            "description": "UUID for idempotency. Auto-generated when omitted."
          }
        },
        "description": "Starts BlindPay's hosted terms-of-service acceptance; the customer returns to `redirect_url` with a `tos_id`.",
        "required": [
          "redirect_url"
        ]
      },
      "KycTermsOfServiceEntity": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "description": "Open it in a browser; the customer returns to `redirect_url` with a `tos_id`.",
            "example": "https://app.blindpay.com/e/terms-of-service?session_token=tos_example"
          }
        },
        "description": "The hosted page where the customer accepts BlindPay's terms of service.",
        "required": [
          "url"
        ]
      },
      "PayerRulesDto": {
        "type": "object",
        "properties": {
          "pix_allowed_tax_ids": {
            "description": "Tax ids of the payers allowed to fund a `pix` payin, forwarded to BlindPay.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "transfers_allowed_tax_id": {
            "type": "string",
            "example": "20123456786",
            "description": "Argentine payer CUIT/CUIL (Transfers 3.0)."
          },
          "pse_allowed_tax_ids": {
            "description": "Tax ids of the payers allowed to fund a `pse` payin, forwarded to BlindPay.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "pse_full_name": {
            "type": "string",
            "example": "Jane Doe",
            "description": "Payer's full name; required for `pse` (Colombia)."
          },
          "pse_document_type": {
            "type": "string",
            "example": "CC",
            "description": "CC | NIT"
          },
          "pse_document_number": {
            "type": "string",
            "example": "123456789",
            "description": "Payer's document number; required for `pse`."
          },
          "pse_email": {
            "type": "string",
            "example": "jane@acme.com",
            "description": "Payer's email address; required for `pse`."
          },
          "pse_phone": {
            "type": "string",
            "example": "+573001234567",
            "description": "Payer's phone number with its country code (`pse`)."
          },
          "pse_bank_code": {
            "type": "string",
            "example": "9",
            "description": "Code of the payer's bank; required for `pse`."
          }
        },
        "description": "Payer details some payin methods require: `transfers` needs `transfers_allowed_tax_id`, `pse` needs the payer's name, document, email and bank."
      },
      "CreatePayinQuoteDto": {
        "type": "object",
        "properties": {
          "blockchain_wallet_id": {
            "type": "string",
            "example": "clz9xwallet001",
            "description": "Cosmos Pay wallet id (from POST /v1/kyc/receivers/:id/wallets) that receives the minted stablecoin."
          },
          "currency_type": {
            "type": "string",
            "enum": [
              "sender",
              "receiver"
            ],
            "example": "sender",
            "description": "Whether `request_amount` is what the sender sends (`sender`) or what the receiver receives (`receiver`)."
          },
          "payment_method": {
            "type": "string",
            "enum": [
              "ach",
              "wire",
              "pix",
              "ted",
              "spei",
              "transfers",
              "pse",
              "international_swift",
              "rtp"
            ],
            "example": "pix",
            "description": "Fiat-in method. Note: payins use `spei`/`transfers`/`pse` (not the `_bitso` payout rails)."
          },
          "token": {
            "type": "string",
            "enum": [
              "USDC",
              "USDT",
              "USDB"
            ],
            "example": "USDC",
            "description": "Stablecoin the wallet receives; `USDB` is the test token of the development instance."
          },
          "request_amount": {
            "type": "number",
            "example": 10000,
            "description": "Amount in minor units (integer)."
          },
          "cover_fees": {
            "type": "boolean",
            "example": false,
            "description": "When true, the sender absorbs the fees."
          },
          "payer_rules": {
            "description": "Required for Transfers (AR): transfers_allowed_tax_id. Required for PSE (CO): pse_full_name, pse_document_type, pse_document_number, pse_email, pse_bank_code. Optional for other methods (e.g. pix).",
            "allOf": [
              {
                "$ref": "#/components/schemas/PayerRulesDto"
              }
            ]
          },
          "is_otc": {
            "type": "boolean",
            "example": false,
            "description": "BlindPay's OTC flag, forwarded as sent."
          },
          "partner_fee_id": {
            "type": "string",
            "description": "BlindPay partner fee id, forwarded as sent."
          },
          "wallet_id": {
            "type": "string",
            "description": "Optional custodial wallet id."
          }
        },
        "description": "A payin (fiat to stablecoin) to price for one of your wallets; the quote expires in about 5 minutes. Amounts are integers in minor units.",
        "required": [
          "blockchain_wallet_id",
          "currency_type",
          "payment_method",
          "token",
          "request_amount"
        ]
      },
      "PayinQuoteEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "pq_000000000000",
            "description": "BlindPay quote id; pass it as `payin_quote_id` to `POST /v1/onramp/payins`."
          },
          "expires_at": {
            "type": "number",
            "example": 1782692400,
            "description": "Unix expiry (~5 min out)."
          },
          "commercial_quotation": {
            "type": "number",
            "example": 5.42,
            "description": "BlindPay's commercial quotation for this quote, passed through as it returned it."
          },
          "receiver_amount": {
            "type": "number",
            "example": 10000,
            "description": "Amount the receiver gets, in minor units."
          },
          "sender_amount": {
            "type": "number",
            "example": 10000,
            "description": "Amount the sender pays, in minor units."
          }
        },
        "description": "A BlindPay payin quote, returned as BlindPay sent it (extra provider fields included); create the payin from `id` before `expires_at`.",
        "required": [
          "id",
          "expires_at"
        ]
      },
      "CreatePayinDto": {
        "type": "object",
        "properties": {
          "payin_quote_id": {
            "type": "string",
            "example": "pq_000000000000",
            "description": "The id returned by POST /v1/onramp/quotes."
          }
        },
        "description": "Executes a payin quote; the answer carries the instructions the payer follows to fund the payin.",
        "required": [
          "payin_quote_id"
        ]
      },
      "PayinEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xpayin0001",
            "description": "Cosmos Pay id of the payin."
          },
          "blindpayId": {
            "type": "string",
            "example": "pi_000000000000",
            "description": "BlindPay's payin id (`pi_...`)."
          },
          "status": {
            "type": "object",
            "example": "processing",
            "description": "BlindPay status of the payin (for example `processing`); `completed`, `failed`, `refunded` and `cancelled` mean the money stopped moving."
          },
          "token": {
            "type": "object",
            "example": "USDC",
            "description": "Stablecoin the payin delivers (for example `USDC`)."
          },
          "network": {
            "type": "object",
            "example": "stellar",
            "description": "Network the stablecoin is delivered on (for example `stellar`)."
          },
          "paymentMethod": {
            "type": "object",
            "example": "pix",
            "description": "Fiat method the payer funds the payin with (for example `pix`)."
          },
          "senderAmount": {
            "type": "object",
            "example": "10000",
            "description": "Amount the payer sends, in minor units, as a string."
          },
          "receiverAmount": {
            "type": "object",
            "example": "9950",
            "description": "Amount the wallet receives, in minor units, as a string."
          },
          "instructions": {
            "type": "object",
            "description": "Funding instructions for the payer (memo/CLABE/PIX/CBU/PSE/...).",
            "example": {
              "pix_code": "00020126...5204000053039865802BR..."
            }
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-28T12:00:00.000Z",
            "description": "When this service recorded the payin (ISO 8601 date-time)."
          }
        },
        "description": "A payin (onramp) as this service mirrors it, with the instructions the payer follows to fund it.",
        "required": [
          "id",
          "blindpayId",
          "createdAt"
        ]
      },
      "PayinListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The payins on this page.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayinEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Matching rows, not the page length.",
            "example": 1
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "The page size applied, from the `take` query parameter (default 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Rows skipped before this page, from the `skip` query parameter (default 0)."
          }
        },
        "description": "One page of the consumer's payins, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "CreateTrustlineDto": {
        "type": "object",
        "properties": {
          "address": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "Stellar address that needs the asset trustline."
          }
        },
        "description": "The Stellar address to build an unsigned trustline transaction for, so it can hold the onramp's stablecoin.",
        "required": [
          "address"
        ]
      },
      "CreateVirtualAccountDto": {
        "type": "object",
        "properties": {
          "banking_partner": {
            "type": "string",
            "enum": [
              "jpmorgan",
              "citi",
              "hsbc",
              "cfsb"
            ],
            "example": "cfsb",
            "description": "Bank the virtual account is opened at."
          },
          "token": {
            "type": "string",
            "enum": [
              "USDC",
              "USDT",
              "USDB"
            ],
            "example": "USDC",
            "description": "Stablecoin the deposits are converted to; `USDB` is the test token of the development instance."
          },
          "blockchain_wallet_id": {
            "type": "string",
            "example": "clz9xwallet001",
            "description": "Cosmos Pay wallet id that receives the converted stablecoin."
          },
          "signed_agreement_id": {
            "type": "string",
            "description": "Id of a signed agreement, forwarded to BlindPay."
          },
          "sole_proprietor_doc_type": {
            "type": "string",
            "description": "Type of the sole-proprietor document, forwarded to BlindPay."
          },
          "sole_proprietor_doc_file": {
            "type": "string",
            "description": "Sole-proprietor document file, forwarded to BlindPay."
          }
        },
        "description": "A virtual account to open for a receiver: a bank account in its name at `banking_partner` whose deposits are converted to `token` and sent to a wallet.",
        "required": [
          "banking_partner",
          "token",
          "blockchain_wallet_id"
        ]
      },
      "CreatePayoutQuoteDto": {
        "type": "object",
        "properties": {
          "bank_account_id": {
            "type": "string",
            "example": "clz9xbank00001",
            "description": "Cosmos Pay bank account id (from POST /v1/kyc/receivers/:id/bank-accounts) that receives the fiat."
          },
          "currency_type": {
            "type": "string",
            "enum": [
              "sender",
              "receiver"
            ],
            "example": "sender",
            "description": "Whether `request_amount` is what the sender sends (`sender`) or what the receiver receives (`receiver`)."
          },
          "cover_fees": {
            "type": "boolean",
            "example": false,
            "description": "When true, the sender absorbs fees."
          },
          "request_amount": {
            "type": "number",
            "example": 10000,
            "description": "Amount in minor units (integer)."
          },
          "network": {
            "type": "string",
            "enum": [
              "ethereum",
              "base",
              "arbitrum",
              "polygon",
              "stellar",
              "solana",
              "tron",
              "sepolia",
              "base_sepolia",
              "arbitrum_sepolia",
              "polygon_amoy",
              "stellar_testnet",
              "solana_devnet"
            ],
            "example": "base",
            "description": "BlindPay network the stablecoin is sent on."
          },
          "token": {
            "type": "string",
            "enum": [
              "USDC",
              "USDT",
              "USDB"
            ],
            "example": "USDC",
            "description": "Stablecoin paid out; `USDB` is the test token of the development instance."
          },
          "description": {
            "type": "string",
            "description": "Free-text description of the payout, forwarded to BlindPay."
          },
          "partner_fee_id": {
            "type": "string",
            "description": "BlindPay partner fee id, forwarded as sent."
          }
        },
        "description": "A payout (stablecoin to fiat) to price to one of your bank accounts; the quote expires in about 5 minutes. Amounts are integers in minor units.",
        "required": [
          "bank_account_id",
          "currency_type",
          "cover_fees",
          "request_amount",
          "network",
          "token"
        ]
      },
      "PayoutQuoteEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "qe_000000000000",
            "description": "BlindPay quote id; pass it as `quote_id` to `POST /v1/offramp/payouts/authorize` and `POST /v1/offramp/payouts`."
          },
          "expires_at": {
            "type": "number",
            "example": 1782692400,
            "description": "Unix expiry (~5 min out)."
          },
          "sender_amount": {
            "type": "number",
            "example": 10000,
            "description": "Amount of stablecoin the sender sends, in minor units."
          },
          "receiver_amount": {
            "type": "number",
            "example": 156129400,
            "description": "Local fiat amount to receive, minor units (e.g. ARS cents)."
          },
          "receiver_local_amount": {
            "type": "number",
            "example": 156129400,
            "description": "Local fiat amount (minor units). Normalized from `receiver_amount` when BlindPay returns 0 here."
          },
          "contract": {
            "type": "object",
            "description": "EVM approve payload to sign (abi, address, functionName, amount, network).",
            "example": {
              "abi": [],
              "address": "0xToken...",
              "functionName": "approve",
              "blindpayContractAddress": "0xBlindPay...",
              "amount": "10000",
              "network": {
                "name": "base",
                "chainId": 8453
              }
            }
          }
        },
        "description": "A BlindPay payout quote, returned as BlindPay sent it; an EVM quote carries the `approve` to sign in `contract`.",
        "required": [
          "id",
          "expires_at"
        ]
      },
      "AuthorizePayoutDto": {
        "type": "object",
        "properties": {
          "quote_id": {
            "type": "string",
            "example": "qe_000000000000",
            "description": "Id of a payout quote from `POST /v1/offramp/quotes`."
          },
          "sender_wallet_address": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "Sender wallet on the selected chain (Stellar G… or Solana base58)."
          },
          "chain": {
            "type": "string",
            "enum": [
              "stellar",
              "solana"
            ],
            "example": "stellar",
            "description": "Chain the payout is sent from: `stellar` or `solana` (EVM payouts skip this step)."
          }
        },
        "description": "Step one of a Stellar or Solana payout: asks BlindPay for the transaction the sender signs.",
        "required": [
          "quote_id",
          "sender_wallet_address",
          "chain"
        ]
      },
      "AuthorizedPayoutEntity": {
        "type": "object",
        "properties": {
          "unsigned_transaction": {
            "type": "string",
            "example": "AAAAAgAAAAB…",
            "description": "The unsigned transaction the customer signs before `POST /v1/offramp/payouts`. Empty when BlindPay returned none."
          }
        },
        "description": "BlindPay's authorize answer for a Stellar or Solana payout, its own fields passed through, with the transaction to sign under `unsigned_transaction`.",
        "required": [
          "unsigned_transaction"
        ]
      },
      "CreatePayoutDto": {
        "type": "object",
        "properties": {
          "quote_id": {
            "type": "string",
            "example": "qe_000000000000",
            "description": "Id of a payout quote from `POST /v1/offramp/quotes`; a quote is paid out at most once."
          },
          "sender_wallet_address": {
            "type": "string",
            "example": "0x1234567890123456789012345678901234567890",
            "description": "Sender wallet on the selected chain (EVM 0x…, Stellar G…, or Solana base58)."
          },
          "chain": {
            "type": "string",
            "enum": [
              "evm",
              "stellar",
              "solana"
            ],
            "example": "evm",
            "description": "Chain family the payout is sent from: `evm`, `stellar` or `solana`."
          },
          "signed_transaction": {
            "type": "string",
            "description": "Required for stellar/solana: signed transaction (Stellar XDR / Solana tx) from POST /v1/offramp/payouts/authorize. Not used for evm."
          }
        },
        "description": "Executes a payout quote. For `evm` the sender has already sent the quote's `approve`; for `stellar` and `solana` send the `signed_transaction` from the authorize step.",
        "required": [
          "quote_id",
          "sender_wallet_address",
          "chain"
        ]
      },
      "PayoutEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "clz9xpayout001",
            "description": "Cosmos Pay id of the payout."
          },
          "blindpayId": {
            "type": "string",
            "example": "pa_000000000000",
            "description": "BlindPay's payout id (`pa_...`)."
          },
          "status": {
            "type": "object",
            "example": "processing",
            "description": "BlindPay status of the payout (for example `processing`); `completed`, `failed`, `refunded` and `cancelled` mean the money stopped moving."
          },
          "token": {
            "type": "object",
            "example": "USDC",
            "description": "Stablecoin paid out (for example `USDC`)."
          },
          "network": {
            "type": "object",
            "example": "base",
            "description": "Network the stablecoin is sent from (for example `base`)."
          },
          "rail": {
            "type": "object",
            "example": "ach",
            "description": "Bank rail the fiat settles on (for example `ach`)."
          },
          "senderAmount": {
            "type": "object",
            "example": "10000",
            "description": "Amount of stablecoin sent, in minor units, as a string."
          },
          "receiverAmount": {
            "type": "object",
            "example": "9900",
            "description": "Fiat amount the bank account receives, in minor units, as a string."
          },
          "senderWalletAddress": {
            "type": "object",
            "example": "0x1234abcd...",
            "description": "Wallet the stablecoin is sent from."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-06-28T12:00:00.000Z",
            "description": "When this service recorded the payout (ISO 8601 date-time)."
          }
        },
        "description": "A payout (offramp) as this service mirrors it.",
        "required": [
          "id",
          "blindpayId",
          "createdAt"
        ]
      },
      "PayoutListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The payouts on this page.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PayoutEntity"
            }
          },
          "total": {
            "type": "number",
            "description": "Matching rows, not the page length.",
            "example": 1
          },
          "take": {
            "type": "number",
            "example": 100,
            "description": "The page size applied, from the `take` query parameter (default 100)."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "Rows skipped before this page, from the `skip` query parameter (default 0)."
          }
        },
        "description": "One page of the consumer's payouts, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "PayoutDocumentDto": {
        "type": "object",
        "properties": {
          "transaction_document_type": {
            "type": "string",
            "example": "invoice",
            "description": "Kind of document (for example `invoice`)."
          },
          "transaction_document_id": {
            "type": "string",
            "example": "INV-2026-001",
            "description": "Identifier of the document itself, such as the invoice number."
          },
          "transaction_document_file": {
            "type": "string",
            "description": "file_url from POST /v1/kyc/upload"
          },
          "description": {
            "type": "string",
            "description": "Free-text description of the document, forwarded to BlindPay."
          }
        },
        "description": "A compliance document backing a payout (an invoice, for example), forwarded to BlindPay.",
        "required": [
          "transaction_document_type",
          "transaction_document_id",
          "transaction_document_file"
        ]
      },
      "DefindexDepositDto": {
        "type": "object",
        "properties": {
          "amounts": {
            "example": [
              "10000000"
            ],
            "description": "One per vault asset, in the asset's minor units: non-negative integer strings no larger than 9007199254740991.",
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "caller": {
            "type": "string",
            "description": "The Stellar account (G...) that deposits: the source of the built transaction, and the account that signs it."
          },
          "invest": {
            "type": "boolean",
            "default": true,
            "description": "Forwarded to DeFindex as the `invest` argument of the vault's `deposit` call."
          },
          "slippageBps": {
            "type": "number",
            "default": 100,
            "minimum": 0,
            "maximum": 10000,
            "description": "Slippage tolerance in basis points (100 = 1%): how far below `amounts` the deposit's minimum amounts may be."
          }
        },
        "description": "Request to build an unsigned deposit into a DeFindex vault for `caller`, to sign unchanged and send to `POST /v1/defindex/submit`.",
        "required": [
          "amounts",
          "caller"
        ]
      },
      "DefindexBuildEntity": {
        "type": "object",
        "properties": {
          "xdr": {
            "type": "string",
            "example": "AAAAAgAAAAB…",
            "description": "The unsigned transaction (base64 envelope XDR), checked here to be the requested call for `caller` and recorded for the submit. Sign it unchanged: any other change makes it a transaction the submit refuses."
          },
          "functionName": {
            "type": "string",
            "example": "deposit",
            "description": "The vault function called."
          },
          "params": {
            "type": "array",
            "items": {},
            "description": "The call's arguments, as DeFindex decoded them."
          },
          "simulationResponse": {
            "type": "object",
            "additionalProperties": true,
            "description": "DeFindex's simulation of the transaction, verbatim."
          }
        },
        "description": "An unsigned DeFindex vault transaction, DeFindex's answer passed through. Only `xdr` matters to a caller: sign it unchanged and submit it; the rest is for display.",
        "required": [
          "xdr",
          "functionName",
          "params",
          "simulationResponse"
        ]
      },
      "DefindexWithdrawDto": {
        "type": "object",
        "properties": {
          "shares": {
            "type": "string",
            "example": "1000000",
            "description": "Vault shares to burn: a non-negative integer string no larger than 9007199254740991."
          },
          "caller": {
            "type": "string",
            "description": "The Stellar account (G...) whose shares are burned: the source of the built transaction, and the account that signs it."
          },
          "slippageBps": {
            "type": "number",
            "default": 100,
            "minimum": 0,
            "maximum": 10000,
            "description": "Slippage tolerance in basis points (100 = 1%), passed to DeFindex for the withdrawal's minimum outputs."
          }
        },
        "description": "Request to build an unsigned withdrawal from a DeFindex vault that burns `caller`'s shares for the vault's underlying assets, to sign unchanged and send to `POST /v1/defindex/submit`.",
        "required": [
          "shares",
          "caller"
        ]
      },
      "DefindexSubmitDto": {
        "type": "object",
        "properties": {
          "xdr": {
            "type": "string",
            "description": "The transaction a DeFindex build on this service returned, signed by `caller` (base64 envelope XDR)."
          }
        },
        "description": "A signed DeFindex transaction to relay: one that a deposit or withdraw build on this service returned to the same API key.",
        "required": [
          "xdr"
        ]
      },
      "DefindexSubmitResultEntity": {
        "type": "object",
        "properties": {
          "txHash": {
            "type": "string",
            "example": "5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a",
            "description": "The transaction hash (64 hex)."
          },
          "success": {
            "type": "boolean",
            "description": "Whether the transaction succeeded on-chain."
          },
          "result": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "example": {
              "type": "vault_deposit",
              "sharesMinted": "9950000"
            },
            "description": "DeFindex's reading of the result: `vault_deposit` with `sharesMinted`, `vault_withdraw` with `amountsOut`, or `unknown` with `value`."
          },
          "ledger": {
            "type": "number",
            "example": 61234567,
            "description": "The ledger it closed in."
          },
          "createdAt": {
            "type": "string",
            "example": "2026-11-01T12:00:00Z",
            "description": "When the transaction was created, as DeFindex reports it (ISO 8601 date-time)."
          },
          "latestLedger": {
            "type": "number",
            "example": 61234570,
            "description": "The latest ledger when DeFindex answered."
          },
          "latestLedgerCloseTime": {
            "type": "string",
            "example": "2026-11-01T12:00:15Z",
            "description": "When `latestLedger` closed, as DeFindex reports it."
          },
          "feeBump": {
            "type": "boolean",
            "example": false,
            "description": "Whether DeFindex reports it as a fee bump transaction."
          },
          "feeCharged": {
            "type": "string",
            "example": "104210",
            "description": "In stroops."
          }
        },
        "description": "DeFindex's answer for a relayed transaction, passed through and stored, so submitting the same transaction again answers it without calling DeFindex.",
        "required": [
          "txHash",
          "success",
          "result",
          "ledger"
        ]
      },
      "CreateProtectedPaymentDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "string",
            "example": "125.50",
            "description": "The amount in USDC, a decimal with up to 7 places, from 1 to 1000000. The fees (1.95% by default) come out of what the merchant receives."
          },
          "releaseModel": {
            "type": "string",
            "enum": [
              "BUYER_RELEASES",
              "MERCHANT_RELEASES",
              "BUYER_APPROVES_MERCHANT_RELEASES"
            ],
            "description": "Who approves delivery and who releases the money: BUYER_RELEASES (the buyer approves and releases), MERCHANT_RELEASES (the merchant does both), BUYER_APPROVES_MERCHANT_RELEASES (the buyer approves, the merchant collects)."
          },
          "deadlinePolicy": {
            "type": "string",
            "enum": [
              "MANUAL_REVIEW",
              "REFUND_BUYER",
              "RELEASE_MERCHANT"
            ],
            "description": "What happens when the delivery deadline passes on a funded payment that was not released: MANUAL_REVIEW (Cosmos Pay ops decides), REFUND_BUYER or RELEASE_MERCHANT (decided automatically)."
          },
          "deliveryWindowHours": {
            "type": "number",
            "minimum": 1,
            "maximum": 2160,
            "example": 168,
            "description": "Hours from funding until the delivery deadline (1 to 2160, 90 days)."
          },
          "fundingWindowHours": {
            "type": "number",
            "default": 72,
            "minimum": 1,
            "maximum": 720,
            "description": "Hours the buyer has to fund it (1 to 720); unfunded after that, it expires."
          },
          "merchantAddress": {
            "type": "string",
            "example": "GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76",
            "description": "The Stellar account (G...) that receives the money. It must trust USDC."
          },
          "buyerAddress": {
            "type": "string",
            "description": "The buyer’s Stellar account (G...), when the merchant knows it. Set, only this account may fund the payment; unset, the first account that funds it is bound as the buyer."
          },
          "title": {
            "type": "string",
            "example": "Order #1042",
            "description": "Shown to the buyer and written into the contract."
          },
          "description": {
            "type": "string",
            "description": "Shown to the buyer and written into the contract."
          },
          "reference": {
            "type": "string",
            "description": "The merchant’s own reference. Never shown to the buyer, never on-chain."
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Optional idempotency key. Prefer the `Idempotency-Key` header; the same key with the same request returns the stored payment, with another request it is 409 `idempotency_conflict`."
          }
        },
        "description": "A protected payment to create: the buyer pays USDC into a Trustless Work contract and it is released to the merchant on the release model chosen here.",
        "required": [
          "amount",
          "releaseModel",
          "deadlinePolicy",
          "deliveryWindowHours",
          "merchantAddress",
          "title"
        ]
      },
      "ProtectedPaymentFeesEntity": {
        "type": "object",
        "properties": {
          "trustlessWorkBps": {
            "type": "number",
            "example": 30,
            "description": "Trustless Work’s fee, in basis points."
          },
          "platformBps": {
            "type": "number",
            "example": 165,
            "description": "Cosmos Pay’s fee, in basis points."
          },
          "totalBps": {
            "type": "number",
            "example": 195,
            "description": "Both fees, in basis points."
          },
          "merchantReceives": {
            "type": "string",
            "example": "123.05275",
            "description": "What the merchant receives on a release, in USDC, after both fees."
          }
        },
        "description": "What the fees take: Trustless Work’s fixed 0.30% and Cosmos Pay’s share, deducted on-chain from a release and from each part of a dispute resolution.",
        "required": [
          "trustlessWorkBps",
          "platformBps",
          "totalBps",
          "merchantReceives"
        ]
      },
      "ProtectedPaymentEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
            "format": "uuid"
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "example": "testnet"
          },
          "status": {
            "type": "string",
            "enum": [
              "CREATED",
              "AWAITING_FUNDING",
              "FUNDED",
              "SHIPPED",
              "APPROVED",
              "RELEASED",
              "DISPUTED",
              "RESOLVED",
              "EXPIRED",
              "CANCELLED"
            ]
          },
          "releaseModel": {
            "type": "string",
            "enum": [
              "BUYER_RELEASES",
              "MERCHANT_RELEASES",
              "BUYER_APPROVES_MERCHANT_RELEASES"
            ]
          },
          "deadlinePolicy": {
            "type": "string",
            "enum": [
              "MANUAL_REVIEW",
              "REFUND_BUYER",
              "RELEASE_MERCHANT"
            ]
          },
          "title": {
            "type": "string",
            "example": "Order #1042"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "string",
            "example": "125.5",
            "description": "In USDC, up to 7 decimals."
          },
          "asset": {
            "type": "string",
            "example": "USDC"
          },
          "assetIssuer": {
            "type": "string",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
          },
          "merchantAddress": {
            "type": "string",
            "example": "GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76",
            "description": "Receives the money."
          },
          "buyerAddress": {
            "type": "string",
            "nullable": true,
            "description": "Named by the merchant, or bound by the first fund."
          },
          "platformFeeBps": {
            "type": "number",
            "example": 165,
            "description": "Cosmos Pay’s fee, in basis points."
          },
          "contractId": {
            "type": "string",
            "nullable": true,
            "example": "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
            "description": "The Trustless Work contract (C...), once deployed by the first fund."
          },
          "fundingExpiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "deliveryWindowHours": {
            "type": "number",
            "example": 168
          },
          "deliveryDeadlineAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time",
            "description": "Funding time plus `deliveryWindowHours`."
          },
          "deadlinePassedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "evidence": {
            "type": "string",
            "nullable": true,
            "description": "What the merchant shipped with (tracking number or URL)."
          },
          "fundedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "shippedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "approvedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "releasedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "disputedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "resolvedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "resolution": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "example": {
              "buyer": "100",
              "merchant": "25.5",
              "decidedBy": "ops@cosmospay.lat"
            },
            "description": "How a dispute split the balance, in USDC before fees."
          },
          "cancelledAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "fees": {
            "$ref": "#/components/schemas/ProtectedPaymentFeesEntity"
          },
          "reference": {
            "type": "string",
            "nullable": true
          },
          "platformAddress": {
            "type": "string",
            "example": "GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76",
            "description": "Cosmos Pay’s platform account."
          },
          "disputeResolverAddress": {
            "type": "string",
            "nullable": true,
            "description": "The dispute resolver the contract names (ops or the automatic resolver)."
          },
          "disputedBy": {
            "type": "string",
            "nullable": true,
            "enum": [
              "BUYER",
              "MERCHANT",
              "DEADLINE"
            ]
          },
          "disputeReason": {
            "type": "string",
            "nullable": true
          },
          "lastSyncedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          },
          "checkoutUrl": {
            "type": "string",
            "example": "https://payments.cosmospay.lat/protected/3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
            "description": "The buyer’s page for this payment: send this link to the buyer."
          }
        },
        "description": "A protected payment as its merchant reads it: the row this service keeps, mirrored from the Trustless Work contract by the sync job.",
        "required": [
          "id",
          "network",
          "status",
          "releaseModel",
          "deadlinePolicy",
          "title",
          "description",
          "amount",
          "asset",
          "assetIssuer",
          "merchantAddress",
          "buyerAddress",
          "platformFeeBps",
          "contractId",
          "fundingExpiresAt",
          "deliveryWindowHours",
          "deliveryDeadlineAt",
          "deadlinePassedAt",
          "evidence",
          "fundedAt",
          "shippedAt",
          "approvedAt",
          "releasedAt",
          "disputedAt",
          "resolvedAt",
          "resolution",
          "cancelledAt",
          "createdAt",
          "fees",
          "reference",
          "platformAddress",
          "disputeResolverAddress",
          "disputedBy",
          "disputeReason",
          "lastSyncedAt",
          "updatedAt",
          "checkoutUrl"
        ]
      },
      "ProtectedPaymentListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ProtectedPaymentEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1
          },
          "take": {
            "type": "number",
            "example": 20
          },
          "skip": {
            "type": "number",
            "example": 0
          }
        },
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "ShipProtectedPaymentDto": {
        "type": "object",
        "properties": {
          "evidence": {
            "type": "string",
            "example": "DHL 1234567890",
            "description": "What the payment shipped with: a tracking number or URL, written into the contract as the milestone’s evidence."
          }
        },
        "required": [
          "evidence"
        ]
      },
      "ProtectedPaymentBuildEntity": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "DEPLOY",
              "FUND",
              "SHIP",
              "APPROVE",
              "RELEASE",
              "DISPUTE",
              "RESOLVE"
            ]
          },
          "xdr": {
            "type": "string",
            "example": "AAAAAgAAAAB…",
            "description": "The unsigned transaction (base64 envelope XDR), checked to be exactly the requested call. Sign it unchanged and send it to the submit route."
          },
          "txHash": {
            "type": "string",
            "example": "5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Submit it before this (15 minutes at most)."
          },
          "protectedPayment": {
            "$ref": "#/components/schemas/ProtectedPaymentEntity"
          }
        },
        "required": [
          "action",
          "xdr",
          "txHash",
          "expiresAt",
          "protectedPayment"
        ]
      },
      "DisputeProtectedPaymentDto": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Why, kept by Cosmos Pay for the review: Trustless Work V1 takes no reason."
          }
        }
      },
      "SubmitProtectedPaymentDto": {
        "type": "object",
        "properties": {
          "protectedPaymentId": {
            "type": "string",
            "format": "uuid",
            "description": "The protected payment the transaction was built for."
          },
          "xdr": {
            "type": "string",
            "description": "The transaction a build on this service returned, signed unchanged (base64 envelope XDR)."
          }
        },
        "required": [
          "protectedPaymentId",
          "xdr"
        ]
      },
      "ProtectedPaymentSubmitEntity": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "DEPLOY",
              "FUND",
              "SHIP",
              "APPROVE",
              "RELEASE",
              "DISPUTE",
              "RESOLVE"
            ]
          },
          "txHash": {
            "type": "string",
            "example": "5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a"
          },
          "status": {
            "type": "string",
            "example": "SUCCESS",
            "description": "Trustless Work’s answer: `SUCCESS` (the payment moved), or `FAILED`."
          },
          "message": {
            "type": "string",
            "nullable": true,
            "example": "The transaction has been successfully sent to the Stellar network."
          },
          "protectedPayment": {
            "$ref": "#/components/schemas/ProtectedPaymentEntity"
          }
        },
        "required": [
          "action",
          "txHash",
          "status",
          "message",
          "protectedPayment"
        ]
      },
      "ProtectedPaymentDisputeChallengeEntity": {
        "type": "object",
        "properties": {
          "message": {
            "type": "string",
            "example": "Cosmos Pay protected payment dispute\npayment: 3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10\naccount: GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76\nnetwork: testnet\nexpires: 2026-11-02T18:10:00.000Z"
          },
          "expiresAt": {
            "type": "string",
            "example": "2026-11-02T18:10:00.000Z"
          }
        },
        "description": "The message a buyer without an on-chain role signs to have the platform open a dispute.",
        "required": [
          "message",
          "expiresAt"
        ]
      },
      "ProtectedPaymentLinkEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "3f1c2b7e-8d4a-4c1e-9b2f-6a5d4c3b2a10",
            "format": "uuid"
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "example": "testnet"
          },
          "status": {
            "type": "string",
            "enum": [
              "CREATED",
              "AWAITING_FUNDING",
              "FUNDED",
              "SHIPPED",
              "APPROVED",
              "RELEASED",
              "DISPUTED",
              "RESOLVED",
              "EXPIRED",
              "CANCELLED"
            ]
          },
          "releaseModel": {
            "type": "string",
            "enum": [
              "BUYER_RELEASES",
              "MERCHANT_RELEASES",
              "BUYER_APPROVES_MERCHANT_RELEASES"
            ]
          },
          "deadlinePolicy": {
            "type": "string",
            "enum": [
              "MANUAL_REVIEW",
              "REFUND_BUYER",
              "RELEASE_MERCHANT"
            ]
          },
          "title": {
            "type": "string",
            "example": "Order #1042"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "amount": {
            "type": "string",
            "example": "125.5",
            "description": "In USDC, up to 7 decimals."
          },
          "asset": {
            "type": "string",
            "example": "USDC"
          },
          "assetIssuer": {
            "type": "string",
            "example": "GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN"
          },
          "merchantAddress": {
            "type": "string",
            "example": "GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76",
            "description": "Receives the money."
          },
          "buyerAddress": {
            "type": "string",
            "nullable": true,
            "description": "Named by the merchant, or bound by the first fund."
          },
          "platformFeeBps": {
            "type": "number",
            "example": 165,
            "description": "Cosmos Pay’s fee, in basis points."
          },
          "contractId": {
            "type": "string",
            "nullable": true,
            "example": "CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75",
            "description": "The Trustless Work contract (C...), once deployed by the first fund."
          },
          "fundingExpiresAt": {
            "type": "string",
            "format": "date-time"
          },
          "deliveryWindowHours": {
            "type": "number",
            "example": 168
          },
          "deliveryDeadlineAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time",
            "description": "Funding time plus `deliveryWindowHours`."
          },
          "deadlinePassedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "evidence": {
            "type": "string",
            "nullable": true,
            "description": "What the merchant shipped with (tracking number or URL)."
          },
          "fundedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "shippedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "approvedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "releasedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "disputedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "resolvedAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "resolution": {
            "type": "object",
            "additionalProperties": true,
            "nullable": true,
            "example": {
              "buyer": "100",
              "merchant": "25.5",
              "decidedBy": "ops@cosmospay.lat"
            },
            "description": "How a dispute split the balance, in USDC before fees."
          },
          "cancelledAt": {
            "type": "string",
            "nullable": true,
            "format": "date-time"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "fees": {
            "$ref": "#/components/schemas/ProtectedPaymentFeesEntity"
          },
          "buyerActions": {
            "type": "array",
            "example": [
              "fund"
            ],
            "description": "What the buyer can do now, by the status and the release model.",
            "items": {
              "type": "string",
              "enum": [
                "fund",
                "approve",
                "release",
                "dispute"
              ]
            }
          },
          "disputeChallenge": {
            "nullable": true,
            "description": "Only when the buyer may dispute and holds no role in the contract (`MERCHANT_RELEASES`): sign `message` with the buyer’s key and send it to dispute.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/ProtectedPaymentDisputeChallengeEntity"
              }
            ]
          }
        },
        "description": "A protected payment as its buyer sees it on the payment link, read without an API key.",
        "required": [
          "id",
          "network",
          "status",
          "releaseModel",
          "deadlinePolicy",
          "title",
          "description",
          "amount",
          "asset",
          "assetIssuer",
          "merchantAddress",
          "buyerAddress",
          "platformFeeBps",
          "contractId",
          "fundingExpiresAt",
          "deliveryWindowHours",
          "deliveryDeadlineAt",
          "deadlinePassedAt",
          "evidence",
          "fundedAt",
          "shippedAt",
          "approvedAt",
          "releasedAt",
          "disputedAt",
          "resolvedAt",
          "resolution",
          "cancelledAt",
          "createdAt",
          "fees",
          "buyerActions",
          "disputeChallenge"
        ]
      },
      "FundProtectedPaymentLinkDto": {
        "type": "object",
        "properties": {
          "buyer": {
            "type": "string",
            "example": "GARMB7W3FCR3GKIM3FLWVJASC2PUZ4VHUJZTNJVWWKNTCJNKO6TBCT76",
            "description": "The buyer’s Stellar account (G...): it signs the deposit and must hold the amount in USDC. The first fund binds it as the buyer."
          }
        },
        "required": [
          "buyer"
        ]
      },
      "ProtectedPaymentLinkBuildEntity": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "DEPLOY",
              "FUND",
              "SHIP",
              "APPROVE",
              "RELEASE",
              "DISPUTE",
              "RESOLVE"
            ]
          },
          "xdr": {
            "type": "string",
            "example": "AAAAAgAAAAB…",
            "description": "The unsigned transaction (base64 envelope XDR), checked to be exactly the requested call. Sign it unchanged and send it to the submit route."
          },
          "txHash": {
            "type": "string",
            "example": "5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a"
          },
          "expiresAt": {
            "type": "string",
            "format": "date-time",
            "description": "Submit it before this (15 minutes at most)."
          },
          "protectedPayment": {
            "$ref": "#/components/schemas/ProtectedPaymentLinkEntity"
          }
        },
        "required": [
          "action",
          "xdr",
          "txHash",
          "expiresAt",
          "protectedPayment"
        ]
      },
      "DisputeProtectedPaymentLinkDto": {
        "type": "object",
        "properties": {
          "reason": {
            "type": "string",
            "description": "Why, kept by Cosmos Pay for the review: Trustless Work V1 takes no reason."
          },
          "signature": {
            "type": "string",
            "description": "Only when the buyer holds no role in the contract (`MERCHANT_RELEASES`): the buyer’s signature (base64) over `disputeChallenge.message` from the link’s read."
          },
          "expiresAt": {
            "type": "string",
            "example": "2026-11-02T18:10:00.000Z",
            "description": "With `signature`: `disputeChallenge.expiresAt`, exactly as it is in the signed message."
          }
        }
      },
      "ProtectedPaymentLinkSubmitEntity": {
        "type": "object",
        "properties": {
          "action": {
            "type": "string",
            "enum": [
              "DEPLOY",
              "FUND",
              "SHIP",
              "APPROVE",
              "RELEASE",
              "DISPUTE",
              "RESOLVE"
            ]
          },
          "txHash": {
            "type": "string",
            "example": "5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a"
          },
          "status": {
            "type": "string",
            "example": "SUCCESS",
            "description": "Trustless Work’s answer: `SUCCESS` (the payment moved), or `FAILED`."
          },
          "message": {
            "type": "string",
            "nullable": true,
            "example": "The transaction has been successfully sent to the Stellar network."
          },
          "protectedPayment": {
            "$ref": "#/components/schemas/ProtectedPaymentLinkEntity"
          }
        },
        "required": [
          "action",
          "txHash",
          "status",
          "message",
          "protectedPayment"
        ]
      },
      "ProtectedPaymentLinkDisputeEntity": {
        "type": "object",
        "properties": {
          "built": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/ProtectedPaymentLinkBuildEntity"
              }
            ]
          },
          "submitted": {
            "nullable": true,
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/ProtectedPaymentLinkSubmitEntity"
              }
            ]
          }
        },
        "description": "A buyer’s dispute: an envelope to sign (`built`) when the buyer holds a role in the contract, or the dispute the platform opened (`submitted`) when it does not."
      },
      "SubmitProtectedPaymentLinkDto": {
        "type": "object",
        "properties": {
          "xdr": {
            "type": "string",
            "description": "The transaction a build of this payment link returned, signed unchanged by the buyer (base64 envelope XDR)."
          }
        },
        "required": [
          "xdr"
        ]
      },
      "ZkTokenEntity": {
        "type": "object",
        "properties": {
          "contractId": {
            "type": "string",
            "example": "CBQU5SGVPPYI5MVBVV5GYTYNHENHBY7J44WYYVDPTZ5UNK6JDEY232QX",
            "description": "The confidential token contract (C...)."
          },
          "symbol": {
            "type": "string",
            "example": "XLM",
            "description": "What it wraps: native XLM."
          },
          "decimals": {
            "type": "number",
            "example": 7,
            "description": "Decimal places of the token's amounts (7, as for XLM)."
          },
          "underlying": {
            "type": "string",
            "example": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
            "description": "Native XLM's Stellar Asset Contract on this network."
          },
          "deployedAtLedger": {
            "type": "number",
            "example": 5387137,
            "description": "The ledger the token was deployed at: where a wallet replays its confidential balance from."
          }
        },
        "description": "Cosmos Pay's confidential token on one network, the token private payments are made on: what a wallet needs to use it.",
        "required": [
          "contractId",
          "symbol",
          "decimals",
          "underlying",
          "deployedAtLedger"
        ]
      },
      "ZkPaymentsConfigEntity": {
        "type": "object",
        "properties": {
          "enabled": {
            "type": "boolean",
            "example": true,
            "description": "Whether private payments run on this network. False until the operator deploys the token there (mainnet today); every other field but `network`, `networkPassphrase`, `auditorId` and `feeBps` is then null."
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "example": "testnet",
            "description": "The network the API key's environment selects."
          },
          "rpcUrl": {
            "type": "string",
            "nullable": true,
            "example": "https://soroban-testnet.stellar.org",
            "description": "The Soroban RPC to build and submit transactions through."
          },
          "networkPassphrase": {
            "type": "string",
            "example": "Test SDF Network ; September 2015",
            "description": "The Stellar network passphrase of `network`."
          },
          "token": {
            "nullable": true,
            "description": "Cosmos Pay's confidential token on this network; null when `enabled` is false.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/ZkTokenEntity"
              }
            ]
          },
          "verifier": {
            "type": "string",
            "nullable": true,
            "example": "CAN45PFA5CVUCU3JB77IE2JNWNTRCDWMRNG55U452L3N2IOCAGOLTUVQ",
            "description": "The UltraHonk verifier registry the token checks proofs with."
          },
          "auditorRegistry": {
            "type": "string",
            "nullable": true,
            "example": "CDKWSGQER4KNDTMZS2W7V4E32KSL7BVM3LBY7EBTPWZZ3SFG5CDAOLF2",
            "description": "The auditor registry holding Cosmos Pay's key."
          },
          "auditorId": {
            "type": "number",
            "example": 0,
            "description": "The auditor id every account on the token registers under."
          },
          "feeBps": {
            "type": "number",
            "example": 18,
            "description": "The commission: 18 bps = 0.18%."
          },
          "feeAccount": {
            "type": "string",
            "nullable": true,
            "example": "GDUYXOQZFVPDVIVBTJNUCGYQEC3XSI2LQOQ3SJWJJ6ZY4JLCJZZFGTNQ",
            "description": "Cosmos Pay's account the commission is transferred to."
          }
        },
        "description": "A network's private payments setup: the token, registries, auditor id, commission and fee account a wallet registers, proves and pays against. Everything in it is public on-chain data or a public URL.",
        "required": [
          "enabled",
          "network",
          "rpcUrl",
          "networkPassphrase",
          "token",
          "verifier",
          "auditorRegistry",
          "auditorId",
          "feeBps",
          "feeAccount"
        ]
      },
      "CreateZkPaymentDto": {
        "type": "object",
        "properties": {
          "amount": {
            "type": "string",
            "description": "What the payer pays in total, in XLM (up to 7 decimal places). The merchant receives it minus the 0.18% commission (`netAmount`); the commission (`feeAmount`, rounded up, at least one stroop) goes to Cosmos Pay's fee account. An amount whose net would be zero is refused.",
            "example": "25.5"
          },
          "recipient": {
            "type": "string",
            "description": "The merchant's Stellar account (G...). It must already hold a confidential account on Cosmos Pay's token, registered under auditor id 0; otherwise the payment is refused with `recipient_not_registered`.",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO"
          },
          "description": {
            "type": "string",
            "description": "Shown to the payer by the checkout. Not secret, and not on-chain: the public read returns it to anyone holding the payment id.",
            "example": "Order #24",
            "maxLength": 280
          },
          "expiresInMinutes": {
            "type": "number",
            "description": "How long the payment stays payable, in minutes. Both transfers must close before it ends.",
            "default": 60,
            "minimum": 1,
            "maximum": 10080
          },
          "idempotencyKey": {
            "type": "string",
            "description": "Idempotency key. A retry with the same key and the same request returns the existing payment; the same key with a different request is 409 idempotency_conflict. The Idempotency-Key header takes precedence over this field. One is generated when neither is sent.",
            "example": "order-24",
            "maxLength": 255
          },
          "merchantFee": {
            "description": "Your own fee on this payment, in XLM, paid privately like the rest: a third confidential transfer from the payer to `wallet`, which must already hold a confidential account on Cosmos Pay's token (under auditor id 0) and be neither the recipient nor the fee account. `paidBy: recipient` takes it from `amount` (the merchant receives less); `payer` adds it on top (the payer pays `amount` plus the fee). The 0.18% commission is a share of `amount` either way. Confirm then takes `merchantFeeTxHash` too.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "Request to create a private payment: an amount in XLM that the payer pays to `recipient` with confidential transfers, which hide it on-chain.",
        "required": [
          "amount",
          "recipient"
        ]
      },
      "ZkPaymentEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cmh4x2k9a0001l70g8v5q3z2w",
            "description": "The private payment id (a cuid)."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUCCEEDED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "As it reads now: a PENDING payment past `expiresAt` reads EXPIRED. It can still settle: transfers that closed before `expiresAt` paid it."
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "example": "testnet",
            "description": "The network the payment is on, set by the API key that created it."
          },
          "tokenContract": {
            "type": "string",
            "example": "CBQU5SGVPPYI5MVBVV5GYTYNHENHBY7J44WYYVDPTZ5UNK6JDEY232QX",
            "description": "The confidential token both transfers must be made on."
          },
          "amount": {
            "type": "string",
            "example": "25.5",
            "description": "What the payer pays in total, in XLM: `netAmount + feeAmount`, plus `merchantFee.amount` when there is one."
          },
          "netAmount": {
            "type": "string",
            "example": "25.49745",
            "description": "What the merchant receives: `amount - feeAmount`, less `merchantFee.amount` when there is one."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.00255",
            "description": "Cosmos Pay's commission, in XLM (decimal string): `feeBps` of the amount the request named (`amount` less a merchant fee with `paidBy: payer`), rounded up to the stroop (0.0000001 XLM) and at least one stroop."
          },
          "feeBps": {
            "type": "number",
            "example": 1,
            "description": "The commission rate the payment was priced at, in basis points (1 = 0.01%)."
          },
          "recipient": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "The merchant (G...)."
          },
          "feeAccount": {
            "type": "string",
            "example": "GDUYXOQZFVPDVIVBTJNUCGYQEC3XSI2LQOQ3SJWJJ6ZY4JLCJZZFGTNQ",
            "description": "Cosmos Pay's account the commission (`feeAmount`) is paid to."
          },
          "payer": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The account both transfers came from, once settled."
          },
          "paymentTxHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The transaction of the transfer that paid `netAmount` to the recipient (64 lowercase hex), once settled."
          },
          "feeTxHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The transaction of the transfer that paid `feeAmount` to the fee account (64 lowercase hex), once settled."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee the request named, paid by a third confidential transfer to its wallet; null without one.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "merchantFeeTxHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The merchant fee's transaction, once settled."
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Order #24",
            "description": "The description given at create, shown to the payer by the checkout; null when none was given."
          },
          "idempotencyKey": {
            "type": "string",
            "example": "order-24",
            "description": "The idempotency key of the create: the one sent (header first, then body), or a generated `zkp_...` key when none was."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T15:00:00.000Z",
            "description": "When the payment stops being payable (ISO 8601 date-time). Every transfer must close before it."
          },
          "settledAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "When the later of the two transfers closed, once settled."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T14:00:00.000Z",
            "description": "When the payment was created (ISO 8601 date-time). A transfer that closed more than a minute before it cannot pay it."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T14:00:00.000Z",
            "description": "When the payment was last changed (ISO 8601 date-time)."
          }
        },
        "description": "A private payment as its owner (the merchant's API key) reads it: the amounts, the accounts to pay, the status and the transactions that settled it.",
        "required": [
          "id",
          "status",
          "network",
          "tokenContract",
          "amount",
          "netAmount",
          "feeAmount",
          "feeBps",
          "recipient",
          "feeAccount",
          "payer",
          "paymentTxHash",
          "feeTxHash",
          "merchantFee",
          "merchantFeeTxHash",
          "description",
          "idempotencyKey",
          "expiresAt",
          "settledAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "ZkPaymentListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The private payments on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ZkPaymentEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "How many private payments match the query, across all pages."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "The page size this page was read with."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "How many matching payments were skipped before this page."
          }
        },
        "description": "One page of the API key's private payments on its network, newest first.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "PublicZkPaymentEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cmh4x2k9a0001l70g8v5q3z2w",
            "description": "The private payment id (a cuid)."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUCCEEDED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "As it reads now: a PENDING payment past `expiresAt` reads EXPIRED, and can still settle with transfers that closed before `expiresAt`."
          },
          "amount": {
            "type": "string",
            "example": "25.5",
            "description": "What the payer pays in total, in XLM (decimal string): `netAmount + feeAmount`, plus `merchantFee.amount` when there is one."
          },
          "netAmount": {
            "type": "string",
            "example": "25.49745",
            "description": "What the merchant receives, in XLM (decimal string): the amount of the transfer to `recipient`."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.00255",
            "description": "Cosmos Pay's commission, in XLM (decimal string): the amount of the transfer to `feeAccount`."
          },
          "feeBps": {
            "type": "number",
            "example": 1,
            "description": "The commission rate the payment was priced at, in basis points (1 = 0.01%)."
          },
          "recipient": {
            "type": "string",
            "example": "GCALNQQBXAPZ2WIRSDDBMSTAKCUH5SG6U76YBFLQLIXJTF7FE5AX7AOO",
            "description": "Transfer `netAmount` here."
          },
          "feeAccount": {
            "type": "string",
            "example": "GDUYXOQZFVPDVIVBTJNUCGYQEC3XSI2LQOQ3SJWJJ6ZY4JLCJZZFGTNQ",
            "description": "Transfer `feeAmount` here, from the same account."
          },
          "merchantFee": {
            "nullable": true,
            "description": "When not null, a third transfer: `merchantFee.amount` to `merchantFee.wallet`, from the same account.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "description": {
            "type": "string",
            "nullable": true,
            "example": "Order #24",
            "description": "The merchant's description of the payment, to show the payer; null when none was given."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T15:00:00.000Z",
            "description": "When the payment stops being payable (ISO 8601 date-time). Every transfer must close before it."
          },
          "network": {
            "type": "string",
            "enum": [
              "public",
              "testnet"
            ],
            "example": "testnet",
            "description": "The network the payment is on, and the transfers must be made on."
          },
          "rpcUrl": {
            "type": "string",
            "example": "https://soroban-testnet.stellar.org",
            "description": "The Soroban RPC to build and submit the transfers through."
          },
          "networkPassphrase": {
            "type": "string",
            "example": "Test SDF Network ; September 2015",
            "description": "The Stellar network passphrase of `network`."
          },
          "token": {
            "description": "The confidential token the transfers are made on.",
            "allOf": [
              {
                "$ref": "#/components/schemas/ZkTokenEntity"
              }
            ]
          },
          "auditorId": {
            "type": "number",
            "example": 0,
            "description": "The auditor id the transfers are encrypted to: Cosmos Pay reads the amount with it to confirm the payment."
          }
        },
        "description": "A private payment as its payer's checkout reads it, with no API key: what to pay, to whom and on which contracts, and the live status to poll. Never the owning merchant account, the idempotency key or the transaction hashes.",
        "required": [
          "id",
          "status",
          "amount",
          "netAmount",
          "feeAmount",
          "feeBps",
          "recipient",
          "feeAccount",
          "merchantFee",
          "description",
          "expiresAt",
          "network",
          "rpcUrl",
          "networkPassphrase",
          "token",
          "auditorId"
        ]
      },
      "ConfirmZkPaymentDto": {
        "type": "object",
        "properties": {
          "paymentTxHash": {
            "type": "string",
            "description": "The transaction of the confidential transfer that paid the merchant the payment's `netAmount` (64 hex).",
            "example": "0bd74f4b2725dc4f5b1c4ddabd7f66d66ac5a613c20f8175f2893eb33e757477"
          },
          "feeTxHash": {
            "type": "string",
            "description": "The transaction of the confidential transfer that paid the fee account the payment's `feeAmount` (64 hex), from the same account.",
            "example": "5f0e8a1d3c7b9e2f4a6c8d0b1e3f5a7c9d2b4e6f8a0c1d3e5f7a9b2c4d6e8f0a"
          },
          "merchantFeeTxHash": {
            "type": "string",
            "description": "Only for a payment with a merchant fee, and then required: the transaction of the confidential transfer that paid `merchantFee.wallet` the payment's `merchantFee.amount` (64 hex), from the same account.",
            "example": "9c2e4a6b8d0f1e3c5a7b9d2f4e6a8c0b1d3f5e7a9c2b4d6f8e0a1c3e5b7d9f2a"
          }
        },
        "description": "The transactions of the confidential transfers that paid a private payment, to verify on-chain and settle it with.",
        "required": [
          "paymentTxHash",
          "feeTxHash"
        ]
      },
      "Usdt0TokenEntity": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "example": "USDT0",
            "description": "The Stellar asset code."
          },
          "issuer": {
            "type": "string",
            "example": "GATISXX6BZ6NC7IKQBY37CJD4SOZL3CYZJWXEDG6JVIY4WBS6KXJHN6Q",
            "description": "The asset's issuer account."
          },
          "contract": {
            "type": "string",
            "example": "CBSJZEIO5C7KC2SF3MKSNXXJSW5G3VTNBX4ATMKUI3B2MR4JKM4R26YF",
            "description": "The asset's Stellar Asset Contract (SAC)."
          }
        },
        "description": "USDT0 on Stellar: the classic asset (code and issuer) and its Stellar Asset Contract.",
        "required": [
          "code",
          "issuer",
          "contract"
        ]
      },
      "Usdt0RouteEntity": {
        "type": "object",
        "properties": {
          "chain": {
            "type": "string",
            "enum": [
              "eth",
              "arb",
              "bera",
              "conflux",
              "flare",
              "hedera",
              "hyperevm",
              "ink",
              "mantle",
              "megaeth",
              "monad",
              "morph",
              "op",
              "plasma",
              "pol",
              "rootstock",
              "sei",
              "stable",
              "tempo",
              "unichain",
              "xlayer"
            ],
            "example": "eth",
            "description": "The id requests name this network with (`to`)."
          },
          "name": {
            "type": "string",
            "example": "Ethereum",
            "description": "The network's display name."
          },
          "eid": {
            "type": "number",
            "example": 30101,
            "description": "LayerZero endpoint id."
          },
          "receives": {
            "type": "string",
            "enum": [
              "USDT",
              "USDT0"
            ],
            "example": "USDT",
            "description": "What arrives: native `USDT` on Ethereum (Tether’s OFT adapter unlocks it), `USDT0` everywhere else."
          }
        },
        "description": "One destination network USDT0 can be sent to from Stellar.",
        "required": [
          "chain",
          "name",
          "eid",
          "receives"
        ]
      },
      "Usdt0RoutesEntity": {
        "type": "object",
        "properties": {
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always `public`: USDT0 exists on Stellar mainnet only."
          },
          "available": {
            "type": "boolean",
            "example": true,
            "description": "Whether this API key can send USDT0: true for a prod (mainnet) key. A dev (testnet) key gets `false` and no routes."
          },
          "token": {
            "description": "USDT0 on Stellar: its classic asset and Stellar Asset Contract.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Usdt0TokenEntity"
              }
            ]
          },
          "oft": {
            "type": "string",
            "example": "CBOWOLFSDM5PZXNFIVDMP5NZ7U2GSIHED6H6R446QOHF266XINKUMMF6",
            "description": "The LayerZero OFT contract the transaction calls (`send`)."
          },
          "eid": {
            "type": "number",
            "example": 30600,
            "description": "Stellar mainnet's LayerZero endpoint id."
          },
          "routes": {
            "description": "The destination networks, Ethereum first and then by name. Empty for a dev (testnet) key.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Usdt0RouteEntity"
            }
          }
        },
        "description": "The networks USDT0 can be sent to from Stellar, with the token and the LayerZero OFT contract a transfer uses.",
        "required": [
          "network",
          "available",
          "token",
          "oft",
          "eid",
          "routes"
        ]
      },
      "QuoteUsdt0Dto": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "enum": [
              "eth",
              "arb",
              "bera",
              "conflux",
              "flare",
              "hedera",
              "hyperevm",
              "ink",
              "mantle",
              "megaeth",
              "monad",
              "morph",
              "op",
              "plasma",
              "pol",
              "rootstock",
              "sei",
              "stable",
              "tempo",
              "unichain",
              "xlayer"
            ],
            "example": "eth",
            "description": "The destination network (`GET /v1/usdt0/routes`). `eth` receives native USDT; every other network receives USDT0."
          },
          "amount": {
            "type": "string",
            "example": "12.5",
            "description": "USDT0 to send, decimal with up to 7 places. The OFT carries 6: a 7th decimal is dust that stays in the account (see `dust`)."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The account that would send it: the quote is simulated as that account. Omitted, a fixed mainnet account is used; the price is the same."
          }
        },
        "description": "A USDT0 quote request: how much USDT0 to send from Stellar, and to which network. The OFT is asked by simulation; nothing is persisted.",
        "required": [
          "to",
          "amount"
        ]
      },
      "Usdt0QuoteEntity": {
        "type": "object",
        "properties": {
          "to": {
            "type": "string",
            "enum": [
              "eth",
              "arb",
              "bera",
              "conflux",
              "flare",
              "hedera",
              "hyperevm",
              "ink",
              "mantle",
              "megaeth",
              "monad",
              "morph",
              "op",
              "plasma",
              "pol",
              "rootstock",
              "sei",
              "stable",
              "tempo",
              "unichain",
              "xlayer"
            ],
            "example": "eth",
            "description": "The destination network id, as requested."
          },
          "eid": {
            "type": "number",
            "example": 30101,
            "description": "The destination network's LayerZero endpoint id."
          },
          "receives": {
            "type": "string",
            "enum": [
              "USDT",
              "USDT0"
            ],
            "example": "USDT",
            "description": "What arrives: native `USDT` on Ethereum, `USDT0` everywhere else."
          },
          "amount": {
            "type": "string",
            "example": "12.5000001",
            "description": "The amount asked for."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "Cosmos Pay's plan commission rate, in basis points. 0 when the deployment has no fee wrapper (USDT0_FEE_WRAPPER): a Soroban transaction has one operation, and only the wrapper can carry a fee."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.0625",
            "description": "The commission in USDT0, out of `amount`: `amount × feeBps / 10,000`, rounded down."
          },
          "amountSent": {
            "type": "string",
            "example": "12.5",
            "description": "What the OFT takes from the account: `amount` without its dust."
          },
          "amountReceived": {
            "type": "string",
            "example": "12.5",
            "description": "What arrives on the destination network (in its token’s 6 decimals). Equal to `amountSent` unless the OFT charges a fee of its own."
          },
          "dust": {
            "type": "string",
            "example": "0.0000001",
            "description": "The 7th decimal the OFT cannot carry (it shares 6 across chains). It stays in the account; nothing is lost."
          },
          "nativeFee": {
            "type": "string",
            "example": "3.6664143",
            "description": "LayerZero’s messaging fee, in XLM, paid by the account on top of the USDT0. It follows LayerZero’s price feeds and changes over time."
          },
          "nativeFeeLimit": {
            "type": "string",
            "example": "4.3996972",
            "description": "What a transfer built now would offer LayerZero, in XLM: `nativeFee` plus a 20% buffer for the minutes before it is signed. What LayerZero does not charge returns to the account in the same transaction, but the account must hold all of it."
          },
          "minAmount": {
            "type": "string",
            "example": "0",
            "description": "The smallest amount the OFT accepts, in USDT0."
          },
          "maxAmount": {
            "type": "string",
            "example": "1844674407370.9551615",
            "description": "The largest amount the OFT accepts, in USDT0."
          }
        },
        "description": "The price of a USDT0 transfer from Stellar: what is sent and arrives, the fees and the OFT's limits. Nothing is persisted.",
        "required": [
          "to",
          "eid",
          "receives",
          "amount",
          "feeBps",
          "feeAmount",
          "amountSent",
          "amountReceived",
          "dust",
          "nativeFee",
          "nativeFeeLimit",
          "minAmount",
          "maxAmount"
        ]
      },
      "CreateUsdt0TransferDto": {
        "type": "object",
        "properties": {
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The Stellar account that holds the USDT0, signs the transaction and pays its fees in XLM (LayerZero fee plus network fee)."
          },
          "to": {
            "type": "string",
            "enum": [
              "eth",
              "arb",
              "bera",
              "conflux",
              "flare",
              "hedera",
              "hyperevm",
              "ink",
              "mantle",
              "megaeth",
              "monad",
              "morph",
              "op",
              "plasma",
              "pol",
              "rootstock",
              "sei",
              "stable",
              "tempo",
              "unichain",
              "xlayer"
            ],
            "example": "eth",
            "description": "The destination network (`GET /v1/usdt0/routes`). `eth` receives native USDT; every other network receives USDT0."
          },
          "recipient": {
            "type": "string",
            "example": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
            "description": "The EVM address credited on the destination network (0x + 40 hex). A mixed-case address must carry a valid EIP-55 checksum."
          },
          "amount": {
            "type": "string",
            "example": "12.5",
            "description": "USDT0 to send, decimal with up to 7 places. The OFT carries 6: a 7th decimal is dust that stays in the account (see `dust`)."
          },
          "idempotencyKey": {
            "type": "string",
            "example": "usdt0-retry-2026-10-25-001",
            "description": "Optional idempotency key. Prefer the `Idempotency-Key` request header; when both are set, the header wins. A retry with the same key and the same request returns the stored transfer; the same key with a different request is 409 `idempotency_conflict`."
          },
          "merchantFee": {
            "description": "Your own fee on this transfer, in USDT0, paid to `wallet` (a Stellar account that trusts USDT0) in the same transaction: the operation is then the fee wrapper (`USDT0_FEE_WRAPPER`), which pays the fee and calls the OFT's `send` under the holder's one authorization. `paidBy: recipient` takes it from `amount` (less is sent); `payer` adds it on top. Without a configured wrapper, `merchant_fee_unsupported`.",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeDto"
              }
            ]
          }
        },
        "description": "A USDT0 transfer from Stellar: the holder, the destination network, the EVM recipient and the amount. The service builds the one Soroban transaction the holder signs and never holds a key.",
        "required": [
          "source",
          "to",
          "recipient",
          "amount"
        ]
      },
      "Usdt0TransferCreatedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm2u0t0transfer0000000001",
            "description": "The transfer's id, used by the read and submit routes."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "DELIVERED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "PENDING: built, waiting for the signature. SUBMITTED: on the Stellar ledger, LayerZero is delivering it. DELIVERED: credited on the destination network. FAILED: the Stellar transaction failed, or LayerZero gave up on the message (`failureReason`). EXPIRED: never reached the ledger before `expiresAt`. A read refreshes a PENDING or SUBMITTED transfer from the ledger and LayerZero Scan."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always mainnet."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The Stellar account that holds the USDT0, signs the transaction and pays its fees in XLM."
          },
          "to": {
            "type": "string",
            "enum": [
              "eth",
              "arb",
              "bera",
              "conflux",
              "flare",
              "hedera",
              "hyperevm",
              "ink",
              "mantle",
              "megaeth",
              "monad",
              "morph",
              "op",
              "plasma",
              "pol",
              "rootstock",
              "sei",
              "stable",
              "tempo",
              "unichain",
              "xlayer"
            ],
            "example": "eth",
            "description": "The destination network id (`GET /v1/usdt0/routes`)."
          },
          "eid": {
            "type": "number",
            "example": 30101,
            "description": "The destination network's LayerZero endpoint id."
          },
          "receives": {
            "type": "string",
            "enum": [
              "USDT",
              "USDT0"
            ],
            "example": "USDT",
            "description": "What arrives: native `USDT` on Ethereum, `USDT0` everywhere else."
          },
          "recipient": {
            "type": "string",
            "example": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
            "description": "The EVM address credited, EIP-55."
          },
          "amount": {
            "type": "string",
            "example": "12.5000001",
            "description": "The amount asked for."
          },
          "amountSent": {
            "type": "string",
            "example": "12.5",
            "description": "What the OFT takes from the account: `amount` without its dust."
          },
          "amountReceived": {
            "type": "string",
            "example": "12.5",
            "description": "What arrives, and the on-chain floor: the transaction fails rather than deliver less."
          },
          "dust": {
            "type": "string",
            "example": "0.0000001",
            "description": "The dust left in the account (`amount` - `amountSent`)."
          },
          "nativeFee": {
            "type": "string",
            "example": "3.6664143",
            "description": "LayerZero’s quoted messaging fee, in XLM."
          },
          "nativeFeeLimit": {
            "type": "string",
            "example": "4.3996972",
            "description": "What the transaction offers LayerZero, in XLM: `nativeFee` plus a 20% buffer. The endpoint charges the real fee and returns the rest to the account in the same transaction."
          },
          "networkFee": {
            "type": "string",
            "example": "1.4468825",
            "description": "The Stellar network fee, in XLM: inclusion plus Soroban resources (part of it is refunded by the network)."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "Cosmos Pay's plan commission rate, in basis points. 0 when the deployment has no fee wrapper (USDT0_FEE_WRAPPER): a Soroban transaction has one operation, and only the wrapper can carry a fee."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.0625",
            "description": "The commission in USDT0, out of `amount`: `amount × feeBps / 10,000`, rounded down."
          },
          "feeWallet": {
            "type": "string",
            "nullable": true,
            "example": "GBFEEWALLETEXAMPLE7XKXBOL5CH6OFGYUMVJZH7H7OZQXK6U2RG3UEZW34",
            "description": "Where the commission went (STELLAR_SWAP_FEE_WALLET); null without one."
          },
          "xdr": {
            "type": "string",
            "description": "The unsigned transaction (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "A SEP-7 `tx` link carrying `xdr`."
          },
          "qr": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "A QR of `uri` as a PNG data URL, or null when the transaction is too large for one, which a Soroban transaction usually is (its ledger footprint makes the XDR several kilobytes). Sign with a connected wallet (Freighter) or the link instead."
          },
          "txHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The Stellar transaction hash once it reached the network (SUBMITTED, DELIVERED, FAILED); null while PENDING or EXPIRED."
          },
          "guid": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "LayerZero’s message id (0x + 64 hex), once the transaction landed."
          },
          "destinationTxHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The destination network’s transaction, once DELIVERED."
          },
          "scanStatus": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "LayerZero Scan’s own status word, verbatim (`INFLIGHT`, `CONFIRMING`, `DELIVERED`, `PAYLOAD_STORED`, ...)."
          },
          "scanUrl": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The transaction on LayerZero Scan (layerzeroscan.com), once it reached the network."
          },
          "failureReason": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Why a FAILED transfer failed."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee the request named, in USDT0, paid to its wallet in this transaction by the fee wrapper; null without one.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "idempotencyKey": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The Idempotency-Key it was created with, if any."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:05:00.000Z",
            "description": "When the transaction's time bounds close: submit refuses it afterwards."
          },
          "submittedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "When it was first seen accepted by the network."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:00:00.000Z",
            "description": "When the transfer was built (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:00:00.000Z",
            "description": "When the transfer was last updated (ISO 8601 date-time)."
          },
          "publicToken": {
            "type": "string",
            "example": "q3Zx0r8vH6c1yJ2bN5mT4kW9sD7fL0aE1gP3uR6iO2w",
            "description": "Only when the caller is the shared public key: this record’s read token. Send it as `X-Record-Token` on the routes of this one record. Reading it by id (and submitting a USDT0 transfer) answers 404 without it; swap submit and cross-chain deposit still accept a request without it for now, and will require it once the deployment turns `PUBLIC_RECORD_TOKEN_REQUIRED_ON_LEGACY` on. The same create replayed with its Idempotency-Key answers the same token. Keep it like the record id: whoever holds both can read the record."
          }
        },
        "description": "A newly built USDT0 transfer, plus its read token when the caller is the shared public key.",
        "required": [
          "id",
          "status",
          "network",
          "source",
          "to",
          "eid",
          "receives",
          "recipient",
          "amount",
          "amountSent",
          "amountReceived",
          "dust",
          "nativeFee",
          "nativeFeeLimit",
          "networkFee",
          "feeBps",
          "feeAmount",
          "feeWallet",
          "xdr",
          "uri",
          "qr",
          "txHash",
          "guid",
          "destinationTxHash",
          "scanStatus",
          "scanUrl",
          "failureReason",
          "merchantFee",
          "idempotencyKey",
          "expiresAt",
          "submittedAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "Usdt0TransferListItemEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm2u0t0transfer0000000001",
            "description": "The transfer's id, used by the read and submit routes."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "DELIVERED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "PENDING: built, waiting for the signature. SUBMITTED: on the Stellar ledger, LayerZero is delivering it. DELIVERED: credited on the destination network. FAILED: the Stellar transaction failed, or LayerZero gave up on the message (`failureReason`). EXPIRED: never reached the ledger before `expiresAt`. A read refreshes a PENDING or SUBMITTED transfer from the ledger and LayerZero Scan."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always mainnet."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The Stellar account that holds the USDT0, signs the transaction and pays its fees in XLM."
          },
          "to": {
            "type": "string",
            "enum": [
              "eth",
              "arb",
              "bera",
              "conflux",
              "flare",
              "hedera",
              "hyperevm",
              "ink",
              "mantle",
              "megaeth",
              "monad",
              "morph",
              "op",
              "plasma",
              "pol",
              "rootstock",
              "sei",
              "stable",
              "tempo",
              "unichain",
              "xlayer"
            ],
            "example": "eth",
            "description": "The destination network id (`GET /v1/usdt0/routes`)."
          },
          "eid": {
            "type": "number",
            "example": 30101,
            "description": "The destination network's LayerZero endpoint id."
          },
          "receives": {
            "type": "string",
            "enum": [
              "USDT",
              "USDT0"
            ],
            "example": "USDT",
            "description": "What arrives: native `USDT` on Ethereum, `USDT0` everywhere else."
          },
          "recipient": {
            "type": "string",
            "example": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
            "description": "The EVM address credited, EIP-55."
          },
          "amount": {
            "type": "string",
            "example": "12.5000001",
            "description": "The amount asked for."
          },
          "amountSent": {
            "type": "string",
            "example": "12.5",
            "description": "What the OFT takes from the account: `amount` without its dust."
          },
          "amountReceived": {
            "type": "string",
            "example": "12.5",
            "description": "What arrives, and the on-chain floor: the transaction fails rather than deliver less."
          },
          "dust": {
            "type": "string",
            "example": "0.0000001",
            "description": "The dust left in the account (`amount` - `amountSent`)."
          },
          "nativeFee": {
            "type": "string",
            "example": "3.6664143",
            "description": "LayerZero’s quoted messaging fee, in XLM."
          },
          "nativeFeeLimit": {
            "type": "string",
            "example": "4.3996972",
            "description": "What the transaction offers LayerZero, in XLM: `nativeFee` plus a 20% buffer. The endpoint charges the real fee and returns the rest to the account in the same transaction."
          },
          "networkFee": {
            "type": "string",
            "example": "1.4468825",
            "description": "The Stellar network fee, in XLM: inclusion plus Soroban resources (part of it is refunded by the network)."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "Cosmos Pay's plan commission rate, in basis points. 0 when the deployment has no fee wrapper (USDT0_FEE_WRAPPER): a Soroban transaction has one operation, and only the wrapper can carry a fee."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.0625",
            "description": "The commission in USDT0, out of `amount`: `amount × feeBps / 10,000`, rounded down."
          },
          "feeWallet": {
            "type": "string",
            "nullable": true,
            "example": "GBFEEWALLETEXAMPLE7XKXBOL5CH6OFGYUMVJZH7H7OZQXK6U2RG3UEZW34",
            "description": "Where the commission went (STELLAR_SWAP_FEE_WALLET); null without one."
          },
          "xdr": {
            "type": "string",
            "description": "The unsigned transaction (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "A SEP-7 `tx` link carrying `xdr`."
          },
          "txHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The Stellar transaction hash once it reached the network (SUBMITTED, DELIVERED, FAILED); null while PENDING or EXPIRED."
          },
          "guid": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "LayerZero’s message id (0x + 64 hex), once the transaction landed."
          },
          "destinationTxHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The destination network’s transaction, once DELIVERED."
          },
          "scanStatus": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "LayerZero Scan’s own status word, verbatim (`INFLIGHT`, `CONFIRMING`, `DELIVERED`, `PAYLOAD_STORED`, ...)."
          },
          "scanUrl": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The transaction on LayerZero Scan (layerzeroscan.com), once it reached the network."
          },
          "failureReason": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Why a FAILED transfer failed."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee the request named, in USDT0, paid to its wallet in this transaction by the fee wrapper; null without one.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "idempotencyKey": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The Idempotency-Key it was created with, if any."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:05:00.000Z",
            "description": "When the transaction's time bounds close: submit refuses it afterwards."
          },
          "submittedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "When it was first seen accepted by the network."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:00:00.000Z",
            "description": "When the transfer was built (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:00:00.000Z",
            "description": "When the transfer was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A USDT0 transfer as the list returns it: every field but `qr`, which only the single read renders.",
        "required": [
          "id",
          "status",
          "network",
          "source",
          "to",
          "eid",
          "receives",
          "recipient",
          "amount",
          "amountSent",
          "amountReceived",
          "dust",
          "nativeFee",
          "nativeFeeLimit",
          "networkFee",
          "feeBps",
          "feeAmount",
          "feeWallet",
          "xdr",
          "uri",
          "txHash",
          "guid",
          "destinationTxHash",
          "scanStatus",
          "scanUrl",
          "failureReason",
          "merchantFee",
          "idempotencyKey",
          "expiresAt",
          "submittedAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "Usdt0TransferListEntity": {
        "type": "object",
        "properties": {
          "data": {
            "description": "The transfers on this page, newest first.",
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Usdt0TransferListItemEntity"
            }
          },
          "total": {
            "type": "number",
            "example": 1,
            "description": "How many transfers match the filter, across all pages."
          },
          "take": {
            "type": "number",
            "example": 20,
            "description": "The page size applied."
          },
          "skip": {
            "type": "number",
            "example": 0,
            "description": "How many matching transfers were skipped before this page."
          }
        },
        "description": "A page of the consumer's USDT0 transfers, newest first, as last refreshed.",
        "required": [
          "data",
          "total",
          "take",
          "skip"
        ]
      },
      "Usdt0TransferEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "cm2u0t0transfer0000000001",
            "description": "The transfer's id, used by the read and submit routes."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "DELIVERED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "PENDING",
            "description": "PENDING: built, waiting for the signature. SUBMITTED: on the Stellar ledger, LayerZero is delivering it. DELIVERED: credited on the destination network. FAILED: the Stellar transaction failed, or LayerZero gave up on the message (`failureReason`). EXPIRED: never reached the ledger before `expiresAt`. A read refreshes a PENDING or SUBMITTED transfer from the ledger and LayerZero Scan."
          },
          "network": {
            "type": "string",
            "example": "public",
            "description": "Always mainnet."
          },
          "source": {
            "type": "string",
            "example": "GA7QYNF7SOWQ3GLR2BGMZEHXAVIRZA4KVWLTJJFC7MGXUA74P7UJVSGZ",
            "description": "The Stellar account that holds the USDT0, signs the transaction and pays its fees in XLM."
          },
          "to": {
            "type": "string",
            "enum": [
              "eth",
              "arb",
              "bera",
              "conflux",
              "flare",
              "hedera",
              "hyperevm",
              "ink",
              "mantle",
              "megaeth",
              "monad",
              "morph",
              "op",
              "plasma",
              "pol",
              "rootstock",
              "sei",
              "stable",
              "tempo",
              "unichain",
              "xlayer"
            ],
            "example": "eth",
            "description": "The destination network id (`GET /v1/usdt0/routes`)."
          },
          "eid": {
            "type": "number",
            "example": 30101,
            "description": "The destination network's LayerZero endpoint id."
          },
          "receives": {
            "type": "string",
            "enum": [
              "USDT",
              "USDT0"
            ],
            "example": "USDT",
            "description": "What arrives: native `USDT` on Ethereum, `USDT0` everywhere else."
          },
          "recipient": {
            "type": "string",
            "example": "0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed",
            "description": "The EVM address credited, EIP-55."
          },
          "amount": {
            "type": "string",
            "example": "12.5000001",
            "description": "The amount asked for."
          },
          "amountSent": {
            "type": "string",
            "example": "12.5",
            "description": "What the OFT takes from the account: `amount` without its dust."
          },
          "amountReceived": {
            "type": "string",
            "example": "12.5",
            "description": "What arrives, and the on-chain floor: the transaction fails rather than deliver less."
          },
          "dust": {
            "type": "string",
            "example": "0.0000001",
            "description": "The dust left in the account (`amount` - `amountSent`)."
          },
          "nativeFee": {
            "type": "string",
            "example": "3.6664143",
            "description": "LayerZero’s quoted messaging fee, in XLM."
          },
          "nativeFeeLimit": {
            "type": "string",
            "example": "4.3996972",
            "description": "What the transaction offers LayerZero, in XLM: `nativeFee` plus a 20% buffer. The endpoint charges the real fee and returns the rest to the account in the same transaction."
          },
          "networkFee": {
            "type": "string",
            "example": "1.4468825",
            "description": "The Stellar network fee, in XLM: inclusion plus Soroban resources (part of it is refunded by the network)."
          },
          "feeBps": {
            "type": "number",
            "example": 50,
            "description": "Cosmos Pay's plan commission rate, in basis points. 0 when the deployment has no fee wrapper (USDT0_FEE_WRAPPER): a Soroban transaction has one operation, and only the wrapper can carry a fee."
          },
          "feeAmount": {
            "type": "string",
            "example": "0.0625",
            "description": "The commission in USDT0, out of `amount`: `amount × feeBps / 10,000`, rounded down."
          },
          "feeWallet": {
            "type": "string",
            "nullable": true,
            "example": "GBFEEWALLETEXAMPLE7XKXBOL5CH6OFGYUMVJZH7H7OZQXK6U2RG3UEZW34",
            "description": "Where the commission went (STELLAR_SWAP_FEE_WALLET); null without one."
          },
          "xdr": {
            "type": "string",
            "description": "The unsigned transaction (base64 XDR) to sign.",
            "example": "AAAAAgAAAABx…(base64 XDR)…AAAAAAAAAAA="
          },
          "uri": {
            "type": "string",
            "example": "web+stellar:tx?xdr=AAAAAgAAAABx…",
            "description": "A SEP-7 `tx` link carrying `xdr`."
          },
          "qr": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "A QR of `uri` as a PNG data URL, or null when the transaction is too large for one, which a Soroban transaction usually is (its ledger footprint makes the XDR several kilobytes). Sign with a connected wallet (Freighter) or the link instead."
          },
          "txHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The Stellar transaction hash once it reached the network (SUBMITTED, DELIVERED, FAILED); null while PENDING or EXPIRED."
          },
          "guid": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "LayerZero’s message id (0x + 64 hex), once the transaction landed."
          },
          "destinationTxHash": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The destination network’s transaction, once DELIVERED."
          },
          "scanStatus": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "LayerZero Scan’s own status word, verbatim (`INFLIGHT`, `CONFIRMING`, `DELIVERED`, `PAYLOAD_STORED`, ...)."
          },
          "scanUrl": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The transaction on LayerZero Scan (layerzeroscan.com), once it reached the network."
          },
          "failureReason": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "Why a FAILED transfer failed."
          },
          "merchantFee": {
            "nullable": true,
            "description": "The merchant fee the request named, in USDT0, paid to its wallet in this transaction by the fee wrapper; null without one.",
            "type": "object",
            "allOf": [
              {
                "$ref": "#/components/schemas/MerchantFeeEntity"
              }
            ]
          },
          "idempotencyKey": {
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "The Idempotency-Key it was created with, if any."
          },
          "expiresAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:05:00.000Z",
            "description": "When the transaction's time bounds close: submit refuses it afterwards."
          },
          "submittedAt": {
            "format": "date-time",
            "type": "string",
            "nullable": true,
            "example": null,
            "description": "When it was first seen accepted by the network."
          },
          "createdAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:00:00.000Z",
            "description": "When the transfer was built (ISO 8601 date-time)."
          },
          "updatedAt": {
            "format": "date-time",
            "type": "string",
            "example": "2026-10-25T12:00:00.000Z",
            "description": "When the transfer was last updated (ISO 8601 date-time)."
          }
        },
        "description": "A USDT0 transfer from Stellar to an EVM network: the stored transfer, its unsigned Soroban transaction and how far LayerZero has delivered it.",
        "required": [
          "id",
          "status",
          "network",
          "source",
          "to",
          "eid",
          "receives",
          "recipient",
          "amount",
          "amountSent",
          "amountReceived",
          "dust",
          "nativeFee",
          "nativeFeeLimit",
          "networkFee",
          "feeBps",
          "feeAmount",
          "feeWallet",
          "xdr",
          "uri",
          "qr",
          "txHash",
          "guid",
          "destinationTxHash",
          "scanStatus",
          "scanUrl",
          "failureReason",
          "merchantFee",
          "idempotencyKey",
          "expiresAt",
          "submittedAt",
          "createdAt",
          "updatedAt"
        ]
      },
      "SubmitUsdt0TransferDto": {
        "type": "object",
        "properties": {
          "signedXdr": {
            "type": "string",
            "description": "The signed transaction envelope (base64 XDR).",
            "example": "AAAAAgAAAABx…(signed base64 XDR)…AAAAAAAAAAA="
          }
        },
        "description": "A USDT0 transfer's transaction, signed, to relay to Stellar mainnet. It must be the transaction the service built (its hash is checked) and carry a signature.",
        "required": [
          "signedXdr"
        ]
      },
      "Usdt0SubmitResultEntity": {
        "type": "object",
        "properties": {
          "submitted": {
            "type": "boolean",
            "example": true,
            "description": "True when the network accepted the transaction (status SUBMITTED, or already DELIVERED)."
          },
          "status": {
            "type": "string",
            "enum": [
              "PENDING",
              "SUBMITTED",
              "DELIVERED",
              "FAILED",
              "EXPIRED"
            ],
            "example": "SUBMITTED",
            "description": "The transfer's status after this submission."
          },
          "txHash": {
            "type": "string",
            "example": "6bc5348acd5dfa908c8d8ff8401d5cce5e659566b0f6707a84950b16ca7410e8",
            "description": "The Stellar transaction hash, once it reached the network."
          },
          "reason": {
            "type": "string",
            "example": null,
            "nullable": true,
            "description": "Why it was not submitted, when `submitted` is false: the network refused it (the transfer stays PENDING and can be submitted again until it expires), or it failed on the ledger (FAILED)."
          },
          "transfer": {
            "description": "The transfer after this submission.",
            "allOf": [
              {
                "$ref": "#/components/schemas/Usdt0TransferEntity"
              }
            ]
          }
        },
        "description": "The result of relaying a signed USDT0 transaction, with the transfer as it stands afterwards.",
        "required": [
          "submitted",
          "status",
          "transfer"
        ]
      },
      "CreateEasyRecoverySessionDto": {
        "type": "object",
        "properties": {
          "receiverKey": {
            "type": "string",
            "description": "The new device’s X25519 public key: 32 bytes, base64url without padding (43 characters). Generate a fresh key pair for every session and keep the private half on the device. The old device seals the wallet to this key, so it reads it from the QR, never from this service.",
            "example": "E75P6uryBMf9M1j8nAByGIHRdCeBKCJ-xnTzf3_pe20",
            "minLength": 43,
            "maxLength": 43
          }
        },
        "description": "Opens an easy-recovery session from the new device, with the key the wallet will be sealed to.",
        "required": [
          "receiverKey"
        ]
      },
      "EasyRecoverySessionCreatedEntity": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The session id: 16 random bytes, base64url (22 characters). Put it in the QR next to `receiverKey`, and nothing else from here.",
            "example": "q2Z7rT0aV1bX9cD4eF6gHw"
          },
          "expiresAt": {
            "type": "string",
            "description": "When the session stops answering, ISO 8601. Five minutes.",
            "example": "2026-10-28T20:05:00.000Z"
          }
        },
        "description": "A new easy-recovery session: its id, for the QR, and when it expires.",
        "required": [
          "id",
          "expiresAt"
        ]
      },
      "EasyRecoverySessionStatusEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "open",
              "offered",
              "claimed"
            ],
            "description": "`open`: waiting for the old device. `offered`: the old device has sent the sealed wallet and shows the code, which the new device asks for it. `claimed`: the new device collected it; the old device can stop.",
            "example": "offered"
          },
          "expiresAt": {
            "type": "string",
            "description": "When the session stops answering, ISO 8601.",
            "example": "2026-10-28T20:05:00.000Z"
          }
        },
        "description": "Where an easy-recovery session stands, polled by both devices.",
        "required": [
          "status",
          "expiresAt"
        ]
      },
      "OfferEasyRecoveryDto": {
        "type": "object",
        "properties": {
          "ciphertext": {
            "type": "string",
            "description": "The wallet’s secret sealed on the old device to the session’s `receiverKey` (ECIES), base64url. This service stores it as given, cannot open it, and hands it out once, to the right code.",
            "minLength": 1,
            "maxLength": 8192
          },
          "code": {
            "type": "string",
            "description": "The five-digit code the old device generated at random and shows on its own screen. Only its hash is stored.",
            "example": "48213",
            "pattern": "^[0-9]{5}$"
          }
        },
        "description": "The old device's offer: the wallet sealed to the session's key, and the code shown on its screen.",
        "required": [
          "ciphertext",
          "code"
        ]
      },
      "EasyRecoveryOfferedEntity": {
        "type": "object",
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "offered"
            ],
            "description": "Always `offered`."
          }
        },
        "description": "Confirmation that the old device's sealed wallet was stored for the session.",
        "required": [
          "status"
        ]
      },
      "ClaimEasyRecoveryDto": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "The five-digit code the person read off the old device. A malformed one is a 400 and costs no attempt; a wrong one costs one of five.",
            "example": "48213",
            "pattern": "^[0-9]{5}$"
          }
        },
        "description": "The new device's claim of the sealed wallet, with the code read off the old device.",
        "required": [
          "code"
        ]
      },
      "EasyRecoveryClaimedEntity": {
        "type": "object",
        "properties": {
          "ciphertext": {
            "type": "string",
            "description": "The sealed wallet exactly as the old device sent it, base64url. Open it with the private key of `receiverKey`. Handed out once: the session reads `claimed` from now on and no longer holds it."
          }
        },
        "description": "The sealed wallet, handed out once to the right code.",
        "required": [
          "ciphertext"
        ]
      },
      "ApiErrorBodyEntity": {
        "type": "object",
        "properties": {
          "statusCode": {
            "type": "number",
            "description": "Always the HTTP status of the response itself.",
            "example": 400
          },
          "code": {
            "type": "string",
            "description": "Stable machine-readable code. Branch on this, never on the message: messages are human-facing and may be reworded; codes are never renamed once published. Each response documents the subset it can return.",
            "enum": [
              "insufficient_scope",
              "no_authenticated_consumer",
              "gateway_required",
              "admin_console_only",
              "not_found",
              "validation_failed",
              "payload_too_large",
              "idempotency_conflict",
              "operation_in_flight",
              "invalid_state_transition",
              "slippage_exceeded",
              "insufficient_balance",
              "no_path_found",
              "trustline_missing",
              "invalid_amount",
              "invalid_memo",
              "transaction_rejected",
              "transaction_already_settled",
              "recipient_not_registered",
              "payment_transfer_mismatch",
              "fee_transfer_mismatch",
              "merchant_fee_transfer_mismatch",
              "payer_mismatch",
              "transaction_not_found",
              "expired",
              "network_unsupported",
              "asset_unsupported",
              "merchant_fee_unsupported",
              "provider_error",
              "provider_unavailable",
              "quote_not_found",
              "quote_expired",
              "kyc_state_invalid",
              "kyc_review_required",
              "account_disabled",
              "payload_expired",
              "rate_limited",
              "customer_wallet_taken",
              "alias_taken",
              "alias_name_invalid",
              "alias_challenge_invalid",
              "alias_signature_invalid",
              "alias_recovery_invalid",
              "alias_address_conflict",
              "wallet_handshake_invalid",
              "wallet_verifier_invalid",
              "wallet_login_code_invalid",
              "wallet_login_code_cooldown",
              "wallet_session_invalid",
              "wallet_signature_invalid",
              "wallet_backup_invalid",
              "wallet_backup_limit",
              "wallet_account_mismatch",
              "wallet_provider_unavailable",
              "wallet_return_url_not_allowed",
              "wallet_recovery_setup_refused",
              "easy_recovery_not_found",
              "easy_recovery_already_offered",
              "easy_recovery_not_offered",
              "easy_recovery_code_invalid",
              "easy_recovery_burned",
              "plugin_not_installed",
              "plugin_consent_mismatch",
              "plugin_rejected",
              "plugin_quota_exceeded",
              "plugin_failed",
              "protected_payment_buyer_mismatch",
              "protected_payment_signature_invalid",
              "misconfigured",
              "internal_error"
            ],
            "example": "validation_failed"
          },
          "error": {
            "type": "string",
            "description": "The HTTP reason phrase for `statusCode`.",
            "example": "Bad Request"
          },
          "message": {
            "description": "Human-readable detail. An array when class-validator rejected the body.",
            "oneOf": [
              {
                "type": "string"
              },
              {
                "type": "array",
                "items": {
                  "type": "string"
                }
              }
            ],
            "example": [
              "amount must be a positive decimal string"
            ]
          },
          "details": {
            "type": "object",
            "description": "Machine-readable facts about this failure, present only on the codes whose example shows it: `easy_recovery_code_invalid` carries `{ \"attemptsLeft\": 4 }`. Absent everywhere else.",
            "additionalProperties": {
              "oneOf": [
                {
                  "type": "string"
                },
                {
                  "type": "number"
                },
                {
                  "type": "boolean"
                }
              ]
            }
          },
          "path": {
            "type": "string",
            "description": "The path of the request that failed.",
            "example": "/v1/swaps"
          },
          "timestamp": {
            "type": "string",
            "description": "When the envelope was produced, ISO 8601.",
            "example": "2026-09-01T12:00:00.000Z"
          }
        },
        "description": "The body of every failed request. Branch on `code`, never on `message`; each response lists the codes it can return.",
        "required": [
          "statusCode",
          "code",
          "error",
          "message",
          "path",
          "timestamp"
        ]
      }
    },
    "responses": {
      "ValidationFailed": {
        "description": "The body, query or path failed validation. `message` is an array of the individual failures.\n\nRoutes that reject a *valid* request for a reason of their own (an amount, a memo, a state) document the code for it on their own 400.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "validation_failed": {
                "summary": "validation_failed: The body, query or headers failed validation",
                "value": {
                  "statusCode": 400,
                  "code": "validation_failed",
                  "error": "Bad Request",
                  "message": [
                    "amount must be a positive decimal string",
                    "destination must be a valid Stellar public key"
                  ],
                  "path": "/v1/swaps",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "Unauthorized": {
        "description": "`no_authenticated_consumer`: The gateway forwarded no API key identity",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "no_authenticated_consumer": {
                "summary": "no_authenticated_consumer: The gateway forwarded no API key identity",
                "value": {
                  "statusCode": 401,
                  "code": "no_authenticated_consumer",
                  "error": "Unauthorized",
                  "message": "No authenticated consumer",
                  "path": "/v1/swaps",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "Forbidden": {
        "description": "`insufficient_scope`: the API key does not hold the scope this route requires. The shared public API key also gets this on every route that is not marked `x-cosmos-public-key`, with a message saying so; more scopes will not help, the key is the wrong one.\n\n`gateway_required`: the request did not arrive through APISIX.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "insufficient_scope": {
                "summary": "insufficient_scope: The API key does not hold the scope this route requires",
                "value": {
                  "statusCode": 403,
                  "code": "insufficient_scope",
                  "error": "Forbidden",
                  "message": "This API key is missing the required scope(s): swaps:write",
                  "path": "/v1/swaps",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              },
              "gateway_required": {
                "summary": "gateway_required: The request did not arrive through the APISIX gateway",
                "value": {
                  "statusCode": 403,
                  "code": "gateway_required",
                  "error": "Forbidden",
                  "message": "Request did not originate from the gateway",
                  "path": "/v1/swaps",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "No such resource, or it exists and belongs to another consumer. The two are deliberately the same answer: \"exists but not yours\" is an ownership oracle.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "not_found": {
                "summary": "not_found: No such resource, or it belongs to another consumer",
                "value": {
                  "statusCode": 404,
                  "code": "not_found",
                  "error": "Not Found",
                  "message": "Payment intent pi_7Yc3Qn0Kx2 not found",
                  "path": "/v1/payment-intents/pi_7Yc3Qn0Kx2",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "The budget in `x-cosmos-rate-limit` is spent for this caller. Honour `Retry-After`.\n\nThe `ratelimit-*` triple rides along on successful responses too, so a client can pace itself instead of being refused. If the counter store itself is unreachable the guard fails closed and answers `503 provider_unavailable`.",
        "headers": {
          "retry-after": {
            "description": "Seconds to wait before retrying. The only one a browser or a naive retry loop honours: prefer it.",
            "schema": {
              "type": "integer",
              "example": 42
            }
          },
          "ratelimit-limit": {
            "description": "Requests allowed in the current window.",
            "schema": {
              "type": "integer",
              "example": 30
            }
          },
          "ratelimit-remaining": {
            "description": "Requests left in the current window.",
            "schema": {
              "type": "integer",
              "example": 0
            }
          },
          "ratelimit-reset": {
            "description": "Seconds until the window resets.",
            "schema": {
              "type": "integer",
              "example": 42
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "rate_limited": {
                "summary": "rate_limited: This route’s budget for this caller is spent",
                "value": {
                  "statusCode": 429,
                  "code": "rate_limited",
                  "error": "Too Many Requests",
                  "message": "Too many requests. Retry in 42s.",
                  "path": "/v1/swaps",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "InternalError": {
        "description": "Unexpected server error. The detail is logged server-side and never returned: there is nothing in the body to branch on beyond the code.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "internal_error": {
                "summary": "internal_error: Unexpected server error (the detail is logged, never returned)",
                "value": {
                  "statusCode": 500,
                  "code": "internal_error",
                  "error": "Internal Server Error",
                  "message": "Internal server error",
                  "path": "/v1/swaps",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "UpstreamError": {
        "description": "The provider named in `x-cosmos-upstream` refused the request (`provider_error`) or could not be reached at all (`provider_unavailable`). Nothing was charged; retry is safe with the same `Idempotency-Key`.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "provider_error": {
                "summary": "provider_error: The upstream provider refused the request",
                "value": {
                  "statusCode": 502,
                  "code": "provider_error",
                  "error": "Bad Gateway",
                  "message": "The payment provider rejected the request.",
                  "path": "/v1/onramp/quotes",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              },
              "provider_unavailable": {
                "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                "value": {
                  "statusCode": 502,
                  "code": "provider_unavailable",
                  "error": "Bad Gateway",
                  "message": "Could not reach the payment provider.",
                  "path": "/v1/onramp/quotes",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "UpstreamUnavailable": {
        "description": "`provider_unavailable`: the provider in `x-cosmos-upstream` is down or unreachable; the message names it. Retry.\n\n`misconfigured`: this deployment is missing configuration the route needs (a provider instance, a fee wallet, the plan header the gateway must forward). Retrying will not help; it is an operator problem.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "provider_unavailable": {
                "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                "value": {
                  "statusCode": 503,
                  "code": "provider_unavailable",
                  "error": "Service Unavailable",
                  "message": "Could not reach the payment provider.",
                  "path": "/v1/onramp/quotes",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              },
              "misconfigured": {
                "summary": "misconfigured: A server-side configuration error: retrying will not help",
                "value": {
                  "statusCode": 503,
                  "code": "misconfigured",
                  "error": "Service Unavailable",
                  "message": "BlindPay (prod) is not configured: set BLINDPAY_INSTANCE_ID_PROD.",
                  "path": "/v1/onramp/quotes",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      },
      "UpstreamTimeout": {
        "description": "The provider in `x-cosmos-upstream` did not answer in time. Whether it acted on the request is unknown. Retry with the same `Idempotency-Key`, never with a fresh one.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiErrorBodyEntity"
            },
            "examples": {
              "provider_unavailable": {
                "summary": "provider_unavailable: The upstream provider could not be reached, or timed out",
                "value": {
                  "statusCode": 504,
                  "code": "provider_unavailable",
                  "error": "Gateway Timeout",
                  "message": "Could not reach the payment provider.",
                  "path": "/v1/onramp/quotes",
                  "timestamp": "2026-09-01T12:00:00.000Z"
                }
              }
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Cosmos Pay developer documentation",
    "url": "https://dev.cosmospay.lat/docs"
  },
  "security": [
    {
      "apiKey": []
    }
  ]
}
