CorebanqCorebanq Developer Docs
FXv1

Get FX convert defaults

Operator-set default currency pair for FX conversion, read from app_config module `fx` (`convert.default_base` / `convert.default_target`) with YAML config fallback. Intended for customer frontends seeding a default FX pair. Only these two whitelisted paths are exposed; an unset default is returned as null, not as an error.

GET
/v1/fx/convert/defaults

Authorization

bearerAuth
AuthorizationBearer <token>

In: header

Response Body

application/json

application/json

application/json

application/json

application/json

application/json

curl -X GET "https://example.com/v1/fx/convert/defaults"
{
  "base": {
    "code": "EUR",
    "precision": 2
  },
  "target": {
    "code": "CHF",
    "precision": 2
  }
}
{
  "status": 409,
  "message": "Spread rule overlaps an existing rule",
  "code": "fx_m.spread_overlap",
  "class": "business",
  "retryable": false,
  "details": [
    {
      "field": "percent_fee",
      "rule": "lte",
      "param": "1",
      "message": "string"
    }
  ]
}
{
  "status": 409,
  "message": "Spread rule overlaps an existing rule",
  "code": "fx_m.spread_overlap",
  "class": "business",
  "retryable": false,
  "details": [
    {
      "field": "percent_fee",
      "rule": "lte",
      "param": "1",
      "message": "string"
    }
  ]
}
{
  "status": 429,
  "message": "Rate limit for 203.0.113.7 to GET:/v1/fx/rates exceeded.",
  "code": "rate_limits_m.exceeded",
  "class": "temporary",
  "retryable": true
}
{
  "status": 409,
  "message": "Spread rule overlaps an existing rule",
  "code": "fx_m.spread_overlap",
  "class": "business",
  "retryable": false,
  "details": [
    {
      "field": "percent_fee",
      "rule": "lte",
      "param": "1",
      "message": "string"
    }
  ]
}

{
  "overall_status": "unhealthy",
  "message": "Service is shutting down",
  "timestamp": "2026-08-27T15:04:05Z"
}

POSTCreate FX tariff fee range

Creates a fee range. Answers 200 with the created row, not 201. Amounts are INTEGER MINOR units; percent_fee is a decimal rate between 0 and 1 and IS validated, so 1.5 is rejected with 400.

GETRetrieve exchange rates

Lists stored rate rows. This route does NOT use the shared query parser and does NOT use the shared list envelope — it has its own parseQueryParams and its own RatesResponse. Pagination is silently clamped rather than validated: limit defaults to 10, is capped at 100, and a non-numeric or non-positive value is IGNORED (the default is used) instead of answering 400. offset defaults to 0 and a negative or non-numeric value is likewise ignored. Results are limited to the currencies the caller is permitted to read; when none are permitted the reply is an empty data set with total 0, not a 403. rate is a quoted decimal STRING in this response — see BaseCurrencyPair. SEARCH FILTERS. Every search.* parameter below is one filter on one column, and the list is the whole set the route accepts. Append an operator to compare instead of match — search.{field}.{op}, op one of eq, ne, gt, gte, lt, lte, in, nin, like, start_with, end_with; with no suffix the operator is eq. in and nin take a comma-separated list. like, start_with and end_with are case-insensitive ILIKE. search.{field}.eq=null and search.{field}.ne=null test for NULL; any other operator with an empty value is 400 query.operator_requires_value. A STRING VALUE IS SILENTLY REWRITTEN BEFORE IT REACHES THE QUERY. sanitizeStringValue drops every character that is not a letter, a digit, or one of . / @ - _ and space, and it never reports an error — so search.provider=A*B filters on AB and answers 200, not 400. A value that parses as a timestamp is passed through instead of stripped. Which rejections are 400 and which are 500 is set out under the 400 and 500 responses; the split is not the one a caller would expect. A DATE-TYPED FILTER IS TRUNCATED TO THE DAY. Where the route's field map types a column as date, normalizeSearchValueByFieldType rewrites the value as YYYY-MM-DD at midnight UTC before it reaches SQL, so a time component on such a filter is discarded without a word. Those parameters carry format: date below; the format: date-time ones are compared as sent.