Skip to content

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.

Example
EXCHANGE_RATES_URL: http://cloud-nine-wallet/rates

The 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.

Example API request (Intra-FSP rate)
GET https://cloud-nine-wallet/rates?base=USD
Example API request (peer rate)
GET https://cloud-nine-wallet/rates?base=USD&peerId=480ef339-7842-4501-a905-923fc1339cef
Query parameterTypeDescriptionRequired
baseStringThe base asset code to get rates for.Y
peerIdStringThe 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.

Example API response
{
"base": "USD",
"rates": {
"EUR": 0.813399,
"MXN": 17.05
}
}
FieldTypeDescriptionRequired
baseStringThe asset code represented as an ISO 4217 currency code, for example USD.Y
ratesObjectObject containing <asset_code : exchange_rate> pairs.Y
rates.<asset_code>NumberThe 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.

Example API request
POST https://rhyza.example.com/rates
Example payload (peer rate)
{
"peerId": "480ef339-7842-4501-a905-923fc1339cef",
"sourceAssetCode": "USD",
"destinationAssetCode": "EUR",
"rate": 0.92,
"rateTtlSecs": 3600
}
Example payload (Intra-FSP rate)
{
"sourceAssetCode": "USD",
"destinationAssetCode": "EUR",
"rate": 0.92,
"rateTtlSecs": 3600
}
FieldTypeDescriptionRequired
peerIdStringThe unique identifier of the peer this rate applies to. Omit to set the Intra-FSP rate instead.N
sourceAssetCodeStringThe source currency code (e.g., “USD”).Y
destinationAssetCodeStringThe destination currency code (e.g., “EUR”).Y
rateNumberThe exchange rate from the source asset to the destination asset.Y
rateTtlSecsNumberThe 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 rateTtlSecs elapses, it’s only replaced the next time that rate is requested, at which point Rhyza falls back to the Pull model synchronously. If rateTtlSecs is 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.

VariableTypeDescriptionDefault
EXCHANGE_RATES_URLURLThe external endpoint used for the Pull model.-
EXCHANGE_RATES_LIFETIME_SECSNumberThe duration (in seconds) Rhyza caches pulled exchange rates.3600
EXCHANGE_RATES_TIMEOUT_SECSNumberThe timeout (in seconds) Rhyza waits when pulling exchange rates from the FSP.10