{
  "openapi": "3.0.3",
  "info": {
    "title": "sondahub Bank API",
    "version": "0.6.1",
    "description": "Retail banking: customers, accounts, cards, nearly eight thousand transactions, transfers and FX rates.\n\nAccounts carry real running balances. POST a transfer between two accounts and the hub debits one, credits the other and writes both transactions; carry the session token and the balances stay moved. FX rates tick over the live stream.\n\nNo keys, no accounts. Writes (POST, PUT, PATCH, DELETE) are validated and answered exactly as a real server would answer them, then forgotten: sondahub stores nothing, and every such answer says so in _note and in the X-Sondahub-Write: simulated header. Every list takes page, limit, sort, q, fields and expand, plus one filter per field with the operators _ne _gt _gte _lt _lte _like _in.",
    "contact": {
      "name": "sondahub",
      "url": "https://api.sondahub.com"
    }
  },
  "servers": [
    {
      "url": "https://api.sondahub.com"
    }
  ],
  "tags": [
    {
      "name": "customers",
      "description": "Account holders."
    },
    {
      "name": "accounts",
      "description": "Checking, savings, credit and loan accounts. balance is the current balance after every transaction."
    },
    {
      "name": "cards",
      "description": "Debit and credit cards on an account. Numbers are masked; the last four are real digits of the seed."
    },
    {
      "name": "transactions",
      "description": "Every movement on an account. amount is signed: negative leaves the account. balance_after is the running balance."
    },
    {
      "name": "transfers",
      "description": "Money moving between two accounts. POST {\"from_account_id\",\"to_account_id\",\"amount\",\"description\"} and the hub checks the funds, debits, credits, and writes both transactions. Insufficient funds answers 422."
    },
    {
      "name": "fx_rates",
      "description": "Exchange rates against USD and the main crosses. The live stream ticks them."
    }
  ],
  "paths": {
    "/v1/bank/customers": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "List customers",
        "operationId": "list_customers",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: accounts, cards.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "name",
            "in": "query",
            "required": false,
            "description": "Filter: name equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "email",
            "in": "query",
            "required": false,
            "description": "Filter: email equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "phone",
            "in": "query",
            "required": false,
            "description": "Filter: phone equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "date_of_birth",
            "in": "query",
            "required": false,
            "description": "Filter: date_of_birth equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date",
              "nullable": true
            }
          },
          {
            "name": "segment",
            "in": "query",
            "required": false,
            "description": "Filter: segment equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "retail",
                "premium",
                "business",
                "student"
              ],
              "nullable": true,
              "example": "retail"
            }
          },
          {
            "name": "kyc_status",
            "in": "query",
            "required": false,
            "description": "Filter: kyc_status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "verified",
                "rejected"
              ],
              "nullable": true,
              "example": "pending"
            }
          },
          {
            "name": "risk_score",
            "in": "query",
            "required": false,
            "description": "Filter: risk_score equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "minimum": 0,
              "maximum": 100
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CustomerList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "customers"
        ],
        "summary": "Create a customer",
        "operationId": "create_customer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/customers/{id}": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "Get a customer",
        "operationId": "get_customer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "customers"
        ],
        "summary": "Replace a customer",
        "operationId": "replace_customer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "customers"
        ],
        "summary": "Update part of a customer",
        "operationId": "update_customer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomerInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "customers"
        ],
        "summary": "Delete a customer",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_customer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/customers/{id}/accounts": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "The accounts of a customer",
        "operationId": "customer_accounts",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of related records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountList"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/customers/{id}/cards": {
      "get": {
        "tags": [
          "customers"
        ],
        "summary": "The cards of a customer",
        "operationId": "customer_cards",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of related records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardList"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/accounts": {
      "get": {
        "tags": [
          "accounts"
        ],
        "summary": "List accounts",
        "operationId": "list_accounts",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: customer, transactions, cards.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "number",
            "in": "query",
            "required": false,
            "description": "Filter: number equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "description": "Unique account number.",
              "example": "SH-0000-4471-9032",
              "readOnly": true
            }
          },
          {
            "name": "iban",
            "in": "query",
            "required": false,
            "description": "Filter: iban equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "readOnly": true
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Filter: customer_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a customer."
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter: type equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "checking",
                "savings",
                "credit",
                "loan"
              ],
              "example": "checking"
            }
          },
          {
            "name": "nickname",
            "in": "query",
            "required": false,
            "description": "Filter: nickname equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "Everyday"
            }
          },
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "description": "Filter: currency equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "USD"
            }
          },
          {
            "name": "balance",
            "in": "query",
            "required": false,
            "description": "Filter: balance equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true,
              "description": "Current balance. Negative on credit and loan accounts means money owed."
            }
          },
          {
            "name": "available",
            "in": "query",
            "required": false,
            "description": "Filter: available equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true,
              "description": "Balance minus holds, or credit left."
            }
          },
          {
            "name": "credit_limit",
            "in": "query",
            "required": false,
            "description": "Filter: credit_limit equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true,
              "description": "Credit accounts only."
            }
          },
          {
            "name": "interest_rate",
            "in": "query",
            "required": false,
            "description": "Filter: interest_rate equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true,
              "description": "Annual, percent."
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "frozen",
                "closed"
              ],
              "nullable": true,
              "example": "active"
            }
          },
          {
            "name": "opened_at",
            "in": "query",
            "required": false,
            "description": "Filter: opened_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AccountList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "accounts"
        ],
        "summary": "Create a account",
        "operationId": "create_account",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/accounts/{id}": {
      "get": {
        "tags": [
          "accounts"
        ],
        "summary": "Get a account",
        "operationId": "get_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "accounts"
        ],
        "summary": "Replace a account",
        "operationId": "replace_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "accounts"
        ],
        "summary": "Update part of a account",
        "operationId": "update_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AccountInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "accounts"
        ],
        "summary": "Delete a account",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/accounts/{id}/customer": {
      "get": {
        "tags": [
          "accounts"
        ],
        "summary": "The customer of a account",
        "operationId": "account_customer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/accounts/{id}/transactions": {
      "get": {
        "tags": [
          "accounts"
        ],
        "summary": "The transactions of a account",
        "operationId": "account_transactions",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of related records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionList"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/accounts/{id}/cards": {
      "get": {
        "tags": [
          "accounts"
        ],
        "summary": "The cards of a account",
        "operationId": "account_cards",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page of related records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardList"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/cards": {
      "get": {
        "tags": [
          "cards"
        ],
        "summary": "List cards",
        "operationId": "list_cards",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: account, customer.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": false,
            "description": "Filter: account_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a account."
            }
          },
          {
            "name": "customer_id",
            "in": "query",
            "required": false,
            "description": "Filter: customer_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a customer."
            }
          },
          {
            "name": "brand",
            "in": "query",
            "required": false,
            "description": "Filter: brand equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "visa",
                "mastercard",
                "amex"
              ],
              "nullable": true,
              "example": "visa"
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter: type equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "debit",
                "credit",
                "virtual"
              ],
              "nullable": true,
              "example": "debit"
            }
          },
          {
            "name": "masked_number",
            "in": "query",
            "required": false,
            "description": "Filter: masked_number equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "•••• •••• •••• 4471",
              "readOnly": true
            }
          },
          {
            "name": "last4",
            "in": "query",
            "required": false,
            "description": "Filter: last4 equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "readOnly": true
            }
          },
          {
            "name": "holder_name",
            "in": "query",
            "required": false,
            "description": "Filter: holder_name equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "expires",
            "in": "query",
            "required": false,
            "description": "Filter: expires equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "example": "09/28"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "blocked",
                "expired",
                "lost"
              ],
              "nullable": true,
              "example": "active"
            }
          },
          {
            "name": "contactless",
            "in": "query",
            "required": false,
            "description": "Filter: contactless equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "boolean",
              "nullable": true
            }
          },
          {
            "name": "daily_limit",
            "in": "query",
            "required": false,
            "description": "Filter: daily_limit equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true,
              "minimum": 0
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CardList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "cards"
        ],
        "summary": "Create a card",
        "operationId": "create_card",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CardInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/cards/{id}": {
      "get": {
        "tags": [
          "cards"
        ],
        "summary": "Get a card",
        "operationId": "get_card",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "cards"
        ],
        "summary": "Replace a card",
        "operationId": "replace_card",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CardInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "cards"
        ],
        "summary": "Update part of a card",
        "operationId": "update_card",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CardInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "cards"
        ],
        "summary": "Delete a card",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_card",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/cards/{id}/account": {
      "get": {
        "tags": [
          "cards"
        ],
        "summary": "The account of a card",
        "operationId": "card_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/cards/{id}/customer": {
      "get": {
        "tags": [
          "cards"
        ],
        "summary": "The customer of a card",
        "operationId": "card_customer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Customer"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transactions": {
      "get": {
        "tags": [
          "transactions"
        ],
        "summary": "List transactions",
        "operationId": "list_transactions",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: -booked_at.",
            "schema": {
              "type": "string",
              "example": "-booked_at"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: account, card.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "account_id",
            "in": "query",
            "required": false,
            "description": "Filter: account_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a account."
            }
          },
          {
            "name": "reference",
            "in": "query",
            "required": false,
            "description": "Filter: reference equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true,
              "description": "Unique.",
              "example": "TXN-8F3A2K9Q",
              "readOnly": true
            }
          },
          {
            "name": "type",
            "in": "query",
            "required": false,
            "description": "Filter: type equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "card",
                "transfer",
                "deposit",
                "withdrawal",
                "fee",
                "interest",
                "payment",
                "refund"
              ],
              "nullable": true,
              "example": "card"
            }
          },
          {
            "name": "amount",
            "in": "query",
            "required": false,
            "description": "Filter: amount equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "description": "Filter: currency equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "balance_after",
            "in": "query",
            "required": false,
            "description": "Filter: balance_after equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true,
              "readOnly": true
            }
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "description": "Filter: description equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "merchant",
            "in": "query",
            "required": false,
            "description": "Filter: merchant equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "category",
            "in": "query",
            "required": false,
            "description": "Filter: category equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "groceries",
                "dining",
                "transport",
                "fuel",
                "shopping",
                "utilities",
                "entertainment",
                "health",
                "travel",
                "subscriptions",
                "transfer",
                "income",
                "fees",
                "other"
              ],
              "nullable": true,
              "example": "groceries"
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "pending",
                "posted",
                "reversed"
              ],
              "nullable": true,
              "example": "pending"
            }
          },
          {
            "name": "card_id",
            "in": "query",
            "required": false,
            "description": "Filter: card_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "The id of a card."
            }
          },
          {
            "name": "booked_at",
            "in": "query",
            "required": false,
            "description": "Filter: booked_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time"
            }
          },
          {
            "name": "value_date",
            "in": "query",
            "required": false,
            "description": "Filter: value_date equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransactionList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "transactions"
        ],
        "summary": "Create a transaction",
        "operationId": "create_transaction",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transaction"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transactions/{id}": {
      "get": {
        "tags": [
          "transactions"
        ],
        "summary": "Get a transaction",
        "operationId": "get_transaction",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transaction"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "transactions"
        ],
        "summary": "Replace a transaction",
        "operationId": "replace_transaction",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transaction"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "transactions"
        ],
        "summary": "Update part of a transaction",
        "operationId": "update_transaction",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransactionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transaction"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "transactions"
        ],
        "summary": "Delete a transaction",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_transaction",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transactions/{id}/account": {
      "get": {
        "tags": [
          "transactions"
        ],
        "summary": "The account of a transaction",
        "operationId": "transaction_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transactions/{id}/card": {
      "get": {
        "tags": [
          "transactions"
        ],
        "summary": "The card of a transaction",
        "operationId": "transaction_card",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Card"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transfers": {
      "get": {
        "tags": [
          "transfers"
        ],
        "summary": "List transfers",
        "operationId": "list_transfers",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: -created_at.",
            "schema": {
              "type": "string",
              "example": "-created_at"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "expand",
            "in": "query",
            "description": "Comma-separated relations to embed: from_account, to_account.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "from_account_id",
            "in": "query",
            "required": false,
            "description": "Filter: from_account_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a account."
            }
          },
          {
            "name": "to_account_id",
            "in": "query",
            "required": false,
            "description": "Filter: to_account_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "description": "The id of a account."
            }
          },
          {
            "name": "amount",
            "in": "query",
            "required": false,
            "description": "Filter: amount equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "minimum": 0.01
            }
          },
          {
            "name": "currency",
            "in": "query",
            "required": false,
            "description": "Filter: currency equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "description",
            "in": "query",
            "required": false,
            "description": "Filter: description equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "nullable": true
            }
          },
          {
            "name": "status",
            "in": "query",
            "required": false,
            "description": "Filter: status equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "enum": [
                "completed",
                "pending",
                "failed",
                "reversed"
              ],
              "nullable": true,
              "example": "completed",
              "readOnly": true
            }
          },
          {
            "name": "debit_transaction_id",
            "in": "query",
            "required": false,
            "description": "Filter: debit_transaction_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "The id of a transaction.",
              "readOnly": true
            }
          },
          {
            "name": "credit_transaction_id",
            "in": "query",
            "required": false,
            "description": "Filter: credit_transaction_id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "The id of a transaction.",
              "readOnly": true
            }
          },
          {
            "name": "scheduled_for",
            "in": "query",
            "required": false,
            "description": "Filter: scheduled_for equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date",
              "nullable": true
            }
          },
          {
            "name": "executed_at",
            "in": "query",
            "required": false,
            "description": "Filter: executed_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "readOnly": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransferList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "transfers"
        ],
        "summary": "Create a transfer",
        "operationId": "create_transfer",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransferInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transfer"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transfers/{id}": {
      "get": {
        "tags": [
          "transfers"
        ],
        "summary": "Get a transfer",
        "operationId": "get_transfer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          },
          {
            "name": "expand",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transfer"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "transfers"
        ],
        "summary": "Replace a transfer",
        "operationId": "replace_transfer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransferInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transfer"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "transfers"
        ],
        "summary": "Update part of a transfer",
        "operationId": "update_transfer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TransferInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Transfer"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "transfers"
        ],
        "summary": "Delete a transfer",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_transfer",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transfers/{id}/from_account": {
      "get": {
        "tags": [
          "transfers"
        ],
        "summary": "The from_account of a transfer",
        "operationId": "transfer_from_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/transfers/{id}/to_account": {
      "get": {
        "tags": [
          "transfers"
        ],
        "summary": "The to_account of a transfer",
        "operationId": "transfer_to_account",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The related record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Account"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/fx_rates": {
      "get": {
        "tags": [
          "fx_rates"
        ],
        "summary": "List fx_rates",
        "operationId": "list_fx_rates",
        "parameters": [
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 200,
              "default": 20
            }
          },
          {
            "name": "sort",
            "in": "query",
            "description": "Comma-separated fields; prefix with - for descending. Default: id.",
            "schema": {
              "type": "string",
              "example": "-id"
            }
          },
          {
            "name": "q",
            "in": "query",
            "description": "Full-text search over the string fields.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "fields",
            "in": "query",
            "description": "Comma-separated fields to return.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "id",
            "in": "query",
            "required": false,
            "description": "Filter: id equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "integer",
              "nullable": true,
              "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
              "readOnly": true
            }
          },
          {
            "name": "created_at",
            "in": "query",
            "required": false,
            "description": "Filter: created_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record was created (ISO 8601, UTC).",
              "readOnly": true
            }
          },
          {
            "name": "updated_at",
            "in": "query",
            "required": false,
            "description": "Filter: updated_at equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true,
              "description": "When the record last changed.",
              "readOnly": true
            }
          },
          {
            "name": "pair",
            "in": "query",
            "required": false,
            "description": "Filter: pair equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "example": "USD/ARS"
            }
          },
          {
            "name": "base",
            "in": "query",
            "required": false,
            "description": "Filter: base equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "example": "USD"
            }
          },
          {
            "name": "quote",
            "in": "query",
            "required": false,
            "description": "Filter: quote equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "example": "ARS"
            }
          },
          {
            "name": "rate",
            "in": "query",
            "required": false,
            "description": "Filter: rate equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number"
            }
          },
          {
            "name": "bid",
            "in": "query",
            "required": false,
            "description": "Filter: bid equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true
            }
          },
          {
            "name": "ask",
            "in": "query",
            "required": false,
            "description": "Filter: ask equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true
            }
          },
          {
            "name": "change_24h_pct",
            "in": "query",
            "required": false,
            "description": "Filter: change_24h_pct equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "number",
              "nullable": true
            }
          },
          {
            "name": "as_of",
            "in": "query",
            "required": false,
            "description": "Filter: as_of equals the value. Suffix the name with _ne, _gt, _gte, _lt, _lte, _like (contains, case-insensitive) or _in (comma list); \"null\" matches missing values.",
            "schema": {
              "type": "string",
              "format": "date-time",
              "nullable": true
            }
          }
        ],
        "responses": {
          "200": {
            "description": "A page.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FxRateList"
                }
              }
            }
          },
          "400": {
            "description": "A parameter could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "fx_rates"
        ],
        "summary": "Create a fx rate",
        "operationId": "create_fx_rate",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FxRateInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created — simulated: the answer is what a real server would give, nothing is stored (see _note and the X-Sondahub-Write header).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FxRate"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/bank/fx_rates/{id}": {
      "get": {
        "tags": [
          "fx_rates"
        ],
        "summary": "Get a fx rate",
        "operationId": "get_fx_rate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "The record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FxRate"
                }
              }
            }
          },
          "304": {
            "description": "Unchanged since the ETag you sent."
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "fx_rates"
        ],
        "summary": "Replace a fx rate",
        "operationId": "replace_fx_rate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FxRateInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FxRate"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "fx_rates"
        ],
        "summary": "Update part of a fx rate",
        "operationId": "update_fx_rate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FxRateInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The record as it would have been saved — simulated, nothing is stored.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FxRate"
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "The body failed validation; details lists each field.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "fx_rates"
        ],
        "summary": "Delete a fx rate",
        "description": "Simulated: answers 200 with the record that would have been removed and a note; nothing is stored.",
        "operationId": "delete_fx_rate",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "integer"
            },
            "example": 1
          }
        ],
        "responses": {
          "200": {
            "description": "What would have been deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean"
                    },
                    "id": {
                      "type": "integer"
                    },
                    "_note": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such record.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string",
                "example": "validation_failed"
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            },
            "required": [
              "code",
              "message"
            ]
          }
        }
      },
      "ListMeta": {
        "type": "object",
        "properties": {
          "page": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pages": {
            "type": "integer"
          }
        }
      },
      "Customer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "date_of_birth": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "address": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { line1, line2?, city, region, postal_code, country }"
          },
          "segment": {
            "type": "string",
            "enum": [
              "retail",
              "premium",
              "business",
              "student"
            ],
            "nullable": true,
            "example": "retail"
          },
          "kyc_status": {
            "type": "string",
            "enum": [
              "pending",
              "verified",
              "rejected"
            ],
            "nullable": true,
            "example": "pending"
          },
          "risk_score": {
            "type": "integer",
            "nullable": true,
            "minimum": 0,
            "maximum": 100
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "name",
          "email"
        ]
      },
      "CustomerInput": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "phone": {
            "type": "string",
            "nullable": true
          },
          "date_of_birth": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "address": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { line1, line2?, city, region, postal_code, country }"
          },
          "segment": {
            "type": "string",
            "enum": [
              "retail",
              "premium",
              "business",
              "student"
            ],
            "nullable": true,
            "example": "retail"
          },
          "kyc_status": {
            "type": "string",
            "enum": [
              "pending",
              "verified",
              "rejected"
            ],
            "nullable": true,
            "example": "pending"
          },
          "risk_score": {
            "type": "integer",
            "nullable": true,
            "minimum": 0,
            "maximum": 100
          }
        },
        "required": [
          "name",
          "email"
        ],
        "example": {
          "name": "A name",
          "email": "A email",
          "segment": "retail",
          "kyc_status": "pending"
        }
      },
      "CustomerList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Customer"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Account": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "number": {
            "type": "string",
            "nullable": true,
            "description": "Unique account number.",
            "example": "SH-0000-4471-9032",
            "readOnly": true
          },
          "iban": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          },
          "customer_id": {
            "type": "integer",
            "description": "The id of a customer."
          },
          "type": {
            "type": "string",
            "enum": [
              "checking",
              "savings",
              "credit",
              "loan"
            ],
            "example": "checking"
          },
          "nickname": {
            "type": "string",
            "nullable": true,
            "example": "Everyday"
          },
          "currency": {
            "type": "string",
            "nullable": true,
            "example": "USD"
          },
          "balance": {
            "type": "number",
            "nullable": true,
            "description": "Current balance. Negative on credit and loan accounts means money owed."
          },
          "available": {
            "type": "number",
            "nullable": true,
            "description": "Balance minus holds, or credit left."
          },
          "credit_limit": {
            "type": "number",
            "nullable": true,
            "description": "Credit accounts only."
          },
          "interest_rate": {
            "type": "number",
            "nullable": true,
            "description": "Annual, percent."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "frozen",
              "closed"
            ],
            "nullable": true,
            "example": "active"
          },
          "opened_at": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "number",
          "iban",
          "customer_id",
          "type"
        ]
      },
      "AccountInput": {
        "type": "object",
        "properties": {
          "customer_id": {
            "type": "integer",
            "description": "The id of a customer."
          },
          "type": {
            "type": "string",
            "enum": [
              "checking",
              "savings",
              "credit",
              "loan"
            ],
            "example": "checking"
          },
          "nickname": {
            "type": "string",
            "nullable": true,
            "example": "Everyday"
          },
          "currency": {
            "type": "string",
            "nullable": true,
            "example": "USD"
          },
          "balance": {
            "type": "number",
            "nullable": true,
            "description": "Current balance. Negative on credit and loan accounts means money owed."
          },
          "available": {
            "type": "number",
            "nullable": true,
            "description": "Balance minus holds, or credit left."
          },
          "credit_limit": {
            "type": "number",
            "nullable": true,
            "description": "Credit accounts only."
          },
          "interest_rate": {
            "type": "number",
            "nullable": true,
            "description": "Annual, percent."
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "frozen",
              "closed"
            ],
            "nullable": true,
            "example": "active"
          },
          "opened_at": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "required": [
          "customer_id",
          "type"
        ],
        "example": {
          "customer_id": 1,
          "type": "checking",
          "nickname": "Everyday",
          "currency": "USD",
          "status": "active"
        }
      },
      "AccountList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Account"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Card": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "customer_id": {
            "type": "integer",
            "description": "The id of a customer."
          },
          "brand": {
            "type": "string",
            "enum": [
              "visa",
              "mastercard",
              "amex"
            ],
            "nullable": true,
            "example": "visa"
          },
          "type": {
            "type": "string",
            "enum": [
              "debit",
              "credit",
              "virtual"
            ],
            "nullable": true,
            "example": "debit"
          },
          "masked_number": {
            "type": "string",
            "nullable": true,
            "example": "•••• •••• •••• 4471",
            "readOnly": true
          },
          "last4": {
            "type": "string",
            "nullable": true,
            "readOnly": true
          },
          "holder_name": {
            "type": "string",
            "nullable": true
          },
          "expires": {
            "type": "string",
            "nullable": true,
            "example": "09/28"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "blocked",
              "expired",
              "lost"
            ],
            "nullable": true,
            "example": "active"
          },
          "contactless": {
            "type": "boolean",
            "nullable": true
          },
          "daily_limit": {
            "type": "number",
            "nullable": true,
            "minimum": 0
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "account_id",
          "customer_id",
          "masked_number",
          "last4"
        ]
      },
      "CardInput": {
        "type": "object",
        "properties": {
          "account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "customer_id": {
            "type": "integer",
            "description": "The id of a customer."
          },
          "brand": {
            "type": "string",
            "enum": [
              "visa",
              "mastercard",
              "amex"
            ],
            "nullable": true,
            "example": "visa"
          },
          "type": {
            "type": "string",
            "enum": [
              "debit",
              "credit",
              "virtual"
            ],
            "nullable": true,
            "example": "debit"
          },
          "holder_name": {
            "type": "string",
            "nullable": true
          },
          "expires": {
            "type": "string",
            "nullable": true,
            "example": "09/28"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "blocked",
              "expired",
              "lost"
            ],
            "nullable": true,
            "example": "active"
          },
          "contactless": {
            "type": "boolean",
            "nullable": true
          },
          "daily_limit": {
            "type": "number",
            "nullable": true,
            "minimum": 0
          }
        },
        "required": [
          "account_id",
          "customer_id"
        ],
        "example": {
          "account_id": 1,
          "customer_id": 1,
          "brand": "visa",
          "type": "debit",
          "expires": "09/28",
          "status": "active"
        }
      },
      "CardList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Card"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Transaction": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "reference": {
            "type": "string",
            "nullable": true,
            "description": "Unique.",
            "example": "TXN-8F3A2K9Q",
            "readOnly": true
          },
          "type": {
            "type": "string",
            "enum": [
              "card",
              "transfer",
              "deposit",
              "withdrawal",
              "fee",
              "interest",
              "payment",
              "refund"
            ],
            "nullable": true,
            "example": "card"
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "balance_after": {
            "type": "number",
            "nullable": true,
            "readOnly": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "merchant": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "enum": [
              "groceries",
              "dining",
              "transport",
              "fuel",
              "shopping",
              "utilities",
              "entertainment",
              "health",
              "travel",
              "subscriptions",
              "transfer",
              "income",
              "fees",
              "other"
            ],
            "nullable": true,
            "example": "groceries"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "posted",
              "reversed"
            ],
            "nullable": true,
            "example": "pending"
          },
          "card_id": {
            "type": "integer",
            "nullable": true,
            "description": "The id of a card."
          },
          "counterparty": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { name, account_number? }"
          },
          "booked_at": {
            "type": "string",
            "format": "date-time"
          },
          "value_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "account_id",
          "reference",
          "amount",
          "balance_after",
          "booked_at"
        ]
      },
      "TransactionInput": {
        "type": "object",
        "properties": {
          "account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "type": {
            "type": "string",
            "enum": [
              "card",
              "transfer",
              "deposit",
              "withdrawal",
              "fee",
              "interest",
              "payment",
              "refund"
            ],
            "nullable": true,
            "example": "card"
          },
          "amount": {
            "type": "number"
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "merchant": {
            "type": "string",
            "nullable": true
          },
          "category": {
            "type": "string",
            "enum": [
              "groceries",
              "dining",
              "transport",
              "fuel",
              "shopping",
              "utilities",
              "entertainment",
              "health",
              "travel",
              "subscriptions",
              "transfer",
              "income",
              "fees",
              "other"
            ],
            "nullable": true,
            "example": "groceries"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "posted",
              "reversed"
            ],
            "nullable": true,
            "example": "pending"
          },
          "card_id": {
            "type": "integer",
            "nullable": true,
            "description": "The id of a card."
          },
          "counterparty": {
            "type": "object",
            "additionalProperties": true,
            "description": "Shape: { name, account_number? }"
          },
          "booked_at": {
            "type": "string",
            "format": "date-time"
          },
          "value_date": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "required": [
          "account_id",
          "amount",
          "booked_at"
        ],
        "example": {
          "account_id": 1,
          "type": "card",
          "amount": 9.99,
          "category": "groceries",
          "status": "pending",
          "booked_at": "2026-09-30T12:00:00Z"
        }
      },
      "TransactionList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transaction"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "Transfer": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "from_account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "to_account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "amount": {
            "type": "number",
            "minimum": 0.01
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "completed",
              "pending",
              "failed",
              "reversed"
            ],
            "nullable": true,
            "example": "completed",
            "readOnly": true
          },
          "debit_transaction_id": {
            "type": "integer",
            "nullable": true,
            "description": "The id of a transaction.",
            "readOnly": true
          },
          "credit_transaction_id": {
            "type": "integer",
            "nullable": true,
            "description": "The id of a transaction.",
            "readOnly": true
          },
          "scheduled_for": {
            "type": "string",
            "format": "date",
            "nullable": true
          },
          "executed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "readOnly": true
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "from_account_id",
          "to_account_id",
          "amount",
          "status",
          "debit_transaction_id",
          "credit_transaction_id",
          "executed_at"
        ]
      },
      "TransferInput": {
        "type": "object",
        "properties": {
          "from_account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "to_account_id": {
            "type": "integer",
            "description": "The id of a account."
          },
          "amount": {
            "type": "number",
            "minimum": 0.01
          },
          "currency": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "scheduled_for": {
            "type": "string",
            "format": "date",
            "nullable": true
          }
        },
        "required": [
          "from_account_id",
          "to_account_id",
          "amount"
        ],
        "example": {
          "from_account_id": 1,
          "to_account_id": 1,
          "amount": 9.99
        }
      },
      "TransferList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Transfer"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      },
      "FxRate": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned by the server. Seed records keep their ids across restarts; records you create continue after the seed.",
            "readOnly": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record was created (ISO 8601, UTC).",
            "readOnly": true
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the record last changed.",
            "readOnly": true
          },
          "pair": {
            "type": "string",
            "example": "USD/ARS"
          },
          "base": {
            "type": "string",
            "example": "USD"
          },
          "quote": {
            "type": "string",
            "example": "ARS"
          },
          "rate": {
            "type": "number"
          },
          "bid": {
            "type": "number",
            "nullable": true
          },
          "ask": {
            "type": "number",
            "nullable": true
          },
          "change_24h_pct": {
            "type": "number",
            "nullable": true
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "id",
          "created_at",
          "updated_at",
          "pair",
          "base",
          "quote",
          "rate"
        ]
      },
      "FxRateInput": {
        "type": "object",
        "properties": {
          "pair": {
            "type": "string",
            "example": "USD/ARS"
          },
          "base": {
            "type": "string",
            "example": "USD"
          },
          "quote": {
            "type": "string",
            "example": "ARS"
          },
          "rate": {
            "type": "number"
          },
          "bid": {
            "type": "number",
            "nullable": true
          },
          "ask": {
            "type": "number",
            "nullable": true
          },
          "change_24h_pct": {
            "type": "number",
            "nullable": true
          },
          "as_of": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        },
        "required": [
          "pair",
          "base",
          "quote",
          "rate"
        ],
        "example": {
          "pair": "USD/ARS",
          "base": "USD",
          "quote": "ARS",
          "rate": 9.99
        }
      },
      "FxRateList": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FxRate"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/ListMeta"
          }
        }
      }
    }
  }
}