Exchange rates
Last reviewed: Oct 2, 2026
If an FSP plans to support cross-currency transactions, they must specify how Rhyza obtains exchange rates.
Rhyza supports two models for handling exchange rates:
- Pull - Rhyza makes a request to an endpoint hosted by the FSP
- Push - The FSP sets the exchange rates via the Admin API directly
A rate probe precedes every Interledger payment to provide a quote that estimates the full cost of transferring value. For cross-currency transactions, Rhyza needs the exchange rates for the currencies involved in the payment.
Every exchange rate Rhyza holds is scoped in one of two ways:
- Peer rate - applies only to payments made through a specific peer, identified by
peerId. - Intra-FSP rate - applies FSP-wide to any conversion between the two given asset codes, independent of peer.
A peer rate and an Intra-FSP rate for the same asset pair are set, cached, and expired independently of one another. Both can be active for the same pair at the same time.
Both Pull and Push models support setting/fetching either scope. Include peerId to target a peer rate, or omit it to target the Intra-FSP rate for that asset pair.
In the pull model, Rhyza requests exchange rates from the FSP whenever a rate is needed and not available in its local cache.
To enable the pull model, configure the EXCHANGE_RATES_URL environment variable for the pal-api-service.
EXCHANGE_RATES_URL: http://cloud-nine-wallet/ratesThe configured endpoint must accept GET requests. Rhyza always includes the base asset code as a query parameter. When Rhyza needs a peer rate rather than the Intra-FSP rate, it also includes a peerId query parameter identifying the peer.
GET https://cloud-nine-wallet/rates?base=USDGET https://cloud-nine-wallet/rates?base=USD&peerId=480ef339-7842-4501-a905-923fc1339cef| Query parameter | Type | Description | Required |
|---|---|---|---|
base | String | The base asset code to get rates for. | Y |
peerId | String | The unique identifier of the peer to get a peer-scoped rate for. Omitted for Intra-FSP rates. | N |
The endpoint must return a JSON response containing the base asset and a mapping of exchange rates for other supported assets.
{ "base": "USD", "rates": { "EUR": 0.813399, "MXN": 17.05 }}| Field | Type | Description | Required |
|---|---|---|---|
base | String | The asset code represented as an ISO 4217 currency code, for example USD. | Y |
rates | Object | Object containing <asset_code : exchange_rate> pairs. | Y |
rates.<asset_code> | Number | The exchange rate relative to the base asset. | Y |
In the push model, the FSP sets exchange rates in Rhyza directly via the Admin API, instead of hosting an external endpoint for Rhyza to query.
Exchange rates are pushed to Rhyza by sending a POST request to the /rates endpoint. Include peerId in the payload to set a peer rate; omit it to set the Intra-FSP rate for the asset pair instead.
POST https://rhyza.example.com/rates{ "peerId": "480ef339-7842-4501-a905-923fc1339cef", "sourceAssetCode": "USD", "destinationAssetCode": "EUR", "rate": 0.92, "rateTtlSecs": 3600}{ "sourceAssetCode": "USD", "destinationAssetCode": "EUR", "rate": 0.92, "rateTtlSecs": 3600}| Field | Type | Description | Required |
|---|---|---|---|
peerId | String | The unique identifier of the peer this rate applies to. Omit to set the Intra-FSP rate instead. | N |
sourceAssetCode | String | The source currency code (e.g., “USD”). | Y |
destinationAssetCode | String | The destination currency code (e.g., “EUR”). | Y |
rate | Number | The exchange rate from the source asset to the destination asset. | Y |
rateTtlSecs | Number | The time-to-live for this rate in seconds. If omitted, a default (3600) is used. | N |
In the Pull model, the FSP can specify how long Rhyza caches exchange rates via the EXCHANGE_RATES_LIFETIME_SECS environment variable (default is 3600 seconds). Caching improves performance by reducing the number of outgoing requests to the FSP’s rates endpoint.
In the Push model, the rateTtlSecs provided in the API request determines the lifetime of the specific rate. If a pushed rate isn’t available or has expired, Rhyza will attempt to pull the rates from the EXCHANGE_RATES_URL, if configured.
If the pull model isn’t configured or also fails to provide a rate, Rhyza will fail the payment or quote request with an error.
Because peer rates and Intra-FSP rates are cached separately, expiry of one doesn’t affect the other, and each is refreshed (via the Pull model) or re-pushed independently.
Pulled and pushed rates expire differently:
- Pulled rates are refreshed proactively in the background shortly before they expire, so a payment or quote isn’t delayed waiting on a live pull.
- Pushed rates are not refreshed in the background. Once a pushed rate’s
rateTtlSecselapses, it’s only replaced the next time that rate is requested, at which point Rhyza falls back to the Pull model synchronously. IfrateTtlSecsis omitted when the rate is pushed, the rate never expires and stays in effect. Rhyza won’t fall back to pulling for that asset pair (or peer) until the FSP pushes a new rate.
The following variables are used by the pal-api-service to manage exchange rates.
| Variable | Type | Description | Default |
|---|---|---|---|
EXCHANGE_RATES_URL | URL | The external endpoint used for the Pull model. | - |
EXCHANGE_RATES_LIFETIME_SECS | Number | The duration (in seconds) Rhyza caches pulled exchange rates. | 3600 |
EXCHANGE_RATES_TIMEOUT_SECS | Number | The timeout (in seconds) Rhyza waits when pulling exchange rates from the FSP. | 10 |