Description
Purpose and use
Currencies define which fiat and crypto denominations the bank can hold, price, display, and validate. They provide the precision rules needed for account balances, transfer amounts, FX rates, tariffs, and ledger postings.
Who uses this. Treasury, operations, product managers, finance controllers, and support teams use currency records when activating new money types and explaining amount precision.
How it works. Each currency carries identity, activity status, display metadata, and precision rules. Those rules determine how major-unit amounts shown to users are converted into minor-unit values used for calculation and posting.
What users do. Users review active currencies, check decimal precision, activate or deactivate supported currencies, and confirm that a product, account, or transfer uses an allowed currency.
Outcomes and side effects. Currency changes affect validation, amount formatting, FX conversion, portfolio totals, and tariff calculation. They do not move money but can allow or block new account and transfer activity.
Related manuals: FX, Accounts & Portfolios, Transfers, Tariffs.
Overview
The currencies package provides functionality for managing supported currencies, exchange rates, and currency conversion operations. It supports ISO 4217 currency codes and maintains real-time exchange rates.
API Methods
Get All Currencies
GET /v1/currencies
Retrieves a list of all supported currencies with their details.
Query Parameters
active- Filter by active status (boolean)region- Filter by region (string)page- Page number for pagination (default: 1)per_page- Items per page (default: 20)
Response
{
"currencies": [
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"code": "EUR",
"numeric_code": "978",
"name": "Euro",
"symbol": "€",
"decimal_places": 2,
"precision": 6,
"is_fiat": true,
"is_base": false,
"format": "€#,##0.00",
"display_priority": 1,
"icon_url": "/data/currencies/eur.svg",
"active": true,
"metadata": {},
"created_at": "2024-03-20T10:00:00Z",
"updated_at": "2024-03-20T10:00:00Z"
}
],
"total": 162,
"page": 1,
"per_page": 20
}Get Currency by ID
GET /v1/currencies/{id}
Retrieves detailed information about a specific currency by its UUID.
Response
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"code": "EUR",
"numeric_code": "978",
"name": "Euro",
"symbol": "€",
"decimal_places": 2,
"precision": 6,
"is_fiat": true,
"is_base": false,
"format": "€#,##0.00",
"display_priority": 1,
"icon_url": "/data/currencies/eur.svg",
"active": true,
"metadata": {},
"created_at": "2024-03-20T10:00:00Z",
"updated_at": "2024-03-20T10:00:00Z"
}Create Currency
POST /v1/currencies
Creates a new currency record.
Update Currency
PUT /v1/currencies/{id}
Updates currency details by ID.
Delete Currency
DELETE /v1/currencies/{id}
Deletes (deactivates) a currency.
Amount & Currency Handling
Design Principles
All monetary amounts in the system are represented as string integers in minor/atomic units. Floating-point numbers are never used for money values.
| Layer | Format |
|---|---|
| Ledger/API | atomic integers |
| UI | formatted decimals |
Why:
- Prevents rounding drift and settlement mismatches
- Deterministic accounting and easy reconciliation
- Regulatory audit safety (traceable, reversible calculations)
Internal Ledger Representation
| Asset | Internal Unit | Precision |
|---|---|---|
| EUR/USD | cents | 2 |
| BTC | satoshis | 8 |
| ETH | wei | 18 |
| USDC | micro | 6 |
API Amount Format
Two Go structs represent amounts across the API:
CcyAmt — used in request bodies (POST / PUT / PATCH):
{
"amount": "123456",
"currency": "EUR"
}CcyAmtWithPrecision — used in all GET responses:
{
"amount": "123456",
"currency": "EUR",
"precision": 2
}Rules
amountis always a string integer in minor/atomic units — never a float.currencyis always present (ISO 4217 for fiat, asset code for crypto).precisionis the number of decimal places the minor unit represents.precisionis server-provided and read-only — the server owns the currency → precision mapping.
GET responses (read)
- Must always include
precisionalongsideamountandcurrency. - Every amount returned by the API is fully self-describing.
POST / PUT / PATCH requests (write)
- Clients send
amountandcurrencyonly. precisionis not accepted in request bodies — the server resolves it from the currency.
FX Rate Format
{
"base": "EUR",
"quote": "USD",
"rate": "1.08532",
"timestamp": "2026-01-01T00:00:00Z"
}- Rate is a decimal string.
- Base currency normalized to 1.
- Stored internally with high precision.
Fees / Tariffs Format
Percentage fees — decimal string:
{
"fee_rate": "0.015"
}Fixed fees — minor-unit integer with precision:
{
"fixed_fee": {
"amount": "30",
"currency": "EUR",
"precision": 2
}
}Common Pitfalls
Precision Mismatch
Crypto assets support up to 18 decimals while fiat typically uses 2. Always convert via atomic units. The explicit precision field eliminates ambiguity during conversions.
FX Conversion Loss
Avoid chained conversions (BTC → EUR → USD). Prefer: atomic ledger → base currency → quote currency.
Regulatory Expectations
Auditors expect deterministic rounding, traceable calculations, and reversible accounting logic. Integer atomic units greatly simplify compliance.
Error Codes
| Code | Description |
|---|---|
| currencies_m.invalid_filter | Invalid filter parameter provided |
| common.failed_to_serialize | Failed to serialize or deserialize request/response payload |
| common.database_error | Internal database error |
| common.forbidden | Access denied – insufficient permissions |
| common.record_not_found | Requested record not found |
Dependencies
common/errs- Error handlingcommon/auth- Authenticationcommon/logger- Logging functionalitycommon/config- Configuration managementmodules/countries- Country-specific currency data