FX Rates
The FXRate
adapter type is invoked when constructing an International Wire. It displays up-to-date exchange rate
information for foreign currencies to United States Dollars.
We create an Adapter extension just as any other:
q2 create_extension
New Extension Name: ConvertToDollars
What type of extension are you creating?
1) Online (default)
2) SSO (Third Party Integration)
3) Ardent (API)
4) Q2Console (Backoffice)
5) Central (Legacy Backoffice)
6) Adapter <--------
7) Audit Action
8) Custom Health Check
9) Message Bus
10) Caliper API Custom Endpoint
11) Base Extension
Please make a selection and press Return [1]: 6
Select adapter type to generate
1) Account Details
2) Authentication Token
3) Check Image
4) Domestic Wire
5) Deposit Item Image
6) External Authentication
7) FX Rate <--------
8) Instant Payments
9) International Wire
10) Remote Deposit
11) Statement Image
Please make a selection and press Return: 7
What did we get? Our extension.py
has the usual boilerplate for a request handler, and a handler class definition with three
methods:
async def get_fx_quote(self, currency_code, amount, group_id) -> FxRateQuoteReply:
async def book_fx_quote(self, currency_code, amount, group_id) -> FxRateExchangeDealReply:
async def cancel_fx_quote(self, currency_code, amount, group_id) -> FxRateExchangeDealReply:
That’s it? From the perspective of an extension developer, yes. By the time this code has executed, the Caliper SDK has:
Intercepted the request from Online
Checked the database for its configured destination
Redirected the request to this Caliper SDK extension
Translated the XML payload containing the request into simple parameters,
currency_code
, andamount
, described above
What you do with these two values, is completely up to you– that’s the power and flexibility of adapters. But, whatever you return will be displayed to the end user as the equivalent amount in USD.

Let’s implement a simple call to a third party that provides FOREX data:
async def get_fx_quote(self, currency_code, amount, group_id) -> FxRateQuoteReply:
"""
Given the three letter currency code and amount, provide the conversion to USD
:param currency_code: The 3 letter currency code as found in the Q2_CurrencyCode table
:param amount: The amount of the currency to be converted
"""
to = "USD"
exchange_rate_api_url = f"https://local-dev-api.q2developer.com/projects/currencyConvert?to={to}&from={currency_code}&amount={amount}"
rate = 0.0
usd_amount = 0.0
response = await q2_requests.get(
self.logger,
exchange_rate_api_url,
headers={
'apikey': 'S6TczFkiWjDZy7FElvqKYMogzdcEcoQy'
}
)
response_as_dict = response.json()
if response_as_dict.get("success"):
usd_amount = response_as_dict.get("result")
rate = response_as_dict.get("info").get('quote')
else:
self.logger.error(response_as_dict.get("message"))
response = FxRateQuoteReply(
status = ReplyStatus.Success,
status_description="Success",
quote_id = "SDF383JD-2332HDS83-332SDD", # ID to be used later during the booking process
base_rate = rate, # (rate not including markup) - must be persisted with transaction for data extract during file creation - new field to store.
exchange_rate = rate+.02, # (rate including markup) - to be included in approval success message
usd_equivalent_amount = usd_amount, # converted fx amount to usd
expiration_date = datetime.now() + timedelta(days=1, hours=3)) # quote is good until
return response
When the usd_amount
is returned, the Caliper SDK will:
Translate the result back into an appropriate XML payload
Send the result through HQ
Display the result in Online banking, for example in the International Wires workflow
More details on the flow can be found in the Architecture section.
This function will be executed as the user is typing in the wire amount in the UI.
Once the user has approved the wire, the book_fx_quote
function will be executed. Same behavior except this time you should actual execute the FX order.
The last function to implement is cancel_fx_quote
. This function will be called if for some reason the order needs to be reversed.
For this to work, we need to install and configure our extension in the database. This is accomplished the same way as
any extension type, q2 install
. The appropriate tables will be updated to re-route adapter requests of the type FXRate
,
coming from anywhere in Q2 platform, to your running extension’s URL.