Lock an Exchange Rate
Locking an exchange rate lets you guarantee the conversion price before executing a transaction protecting you and your users from market fluctuations between quote and execution.
All three flows: payins, payout, and bulk exchange: follow the same two-step pattern:
- Get a quote: Call the Currency Exchange Quote API specifying the operation type (
payin,payout, orCurrencyExchange). You'll receive anexchangeRateTokenwith a guaranteed rate and an expiration time. - Use the token: Include the
exchangeRateTokenin your payin, payout, or bulk exchange request. The API applies the locked rate automatically.
The sections below use a payin as the example, but the structure is similar for payouts and bulk exchange.
Rate expiration
The locked rate is only guaranteed until the token's
expirationDate. If the token expires before you submit the transaction, the operation will use the market rate at that moment.
Quote a Payin
Use this flow when you want to show the exchange rate to your user before collecting a payment.
Step 1: Request a quote
Request
curl --request GET \
--url 'https://api.stage.localpayment.com/api/fx/currency-exchange/payin?sourceCurrency=ARS"eCurrency=USD&accountNumber={{accountNumber}}"eAccountNumber={{accountNumber}}' \
--header 'Authorization: Bearer <your_access_token>' \
--header 'accept: application/json'Response
{
"exchangeRateToken": "5c3q89a7-f1bc-4ba5-a3b5-411ba0d144ca",
"transactionType": "PayIn",
"accountNumber": "{{accountNumber}}",
"sourceCurrency": "ARS",
"creationDate": "2024-12-27T21:33:32.6513692+00:00",
"expirationDate": "2024-12-28T05:33:32.6513692+00:00",
"quotes": [
{
"paymentMethodCode": "1005",
"rate": 0.0008369108482392735,
"quoteCurrency": "USD"
},
{
"paymentMethodCode": "1023",
"rate": 0.0008369108482392735,
"quoteCurrency": "USD"
},
{
"paymentMethodCode": "1000",
"rate": 0.0008369108482392735,
"quoteCurrency": "USD"
}
]
}Step 2: Submit the payin with the token
Request
curl --request POST \
--url https://api.stage.localpayment.com/api/payin/ \
--header 'accept: application/json' \
--header 'content-type: application/json' \
--data '
{
"paymentMethod": {
"type": "CreditCard",
"code": "1000",
"flow": "DIRECT"
},
"externalId": "4423f38d-cc35-4ca9-8119-b9102059172d",
"country": "ARG",
"currency": "ARS",
"amount": 100,
"accountNumber": "{{accountNumber}}",
"conceptCode": "0001",
"comment": "APPROVED",
"exchangeRateToken": "5c3q89a7-f1bc-4ba5-a3b5-411ba0d144ca,
"merchant": {
"type": "COMPANY",
"name": "Company",
"document": {
"id": "3000091105",
"type": "CUIT"
}
},
"payer": {
"type": "INDIVIDUAL",
"name": "John",
"lastname": "Doe",
"document": {
"id": "37993123",
"type": "DNI"
},
"email": "[email protected]",
"phone": {
"countryCode": "1",
"areaCode": "11",
"number": "98189123"
},
"bank": {
"account": {
"type": "C"
}
}
},
"metaData": {
"1finalStatus": "APPROVED",
"2finalStatus": "INPROGRESS"
},
"card": {
"name": "APPRO",
"number": "4970100000000055",
"cvv": "123",
"expirationMonth": "11",
"expirationYear": "2029",
"installments": 1,
"save": false
}
}
'Response
{
"transactionType": "PayIn",
"externalId": "949e5683-4320-4129-bf0a-ea3b027b6cd1",
"internalId": "22b29c98-92af-44bd-a164-1863ae2f1bb3",
"paymentMethod": {
"type": "CreditCard",
"code": "1000",
"flow": "DIRECT"
},
"country": "ARG",
"currency": "ARS",
"amount": 1002,
"accountNumber": "{{accountNumber}}",
"confirmed": {
"currency": "ARS",
"amount": 1002,
"fxQuote": 1,
"exchangeRateToken": null
},
"payment": {
"installment": null,
"currency": "ARS",
"fxQuote": 1,
"financingFee": 0,
"amount": 1002
},
"localTaxes": [],
"withHoldings": [],
"fees": {
"description": "Fee",
"currency": "ARS",
"fxSource": 210.8,
"fxQuote": 1,
"amount": 13.02,
"account": "{{accountNumber}}"
},
"status": {
"code": "103",
"description": "APPROVED",
"detail": "The payin was confirmed but not credited yet"
},
"ticket": null,
"qr": null,
"beneficiary": null,
"merchant": {
"type": "COMPANY",
"name": "Company"
},
"payer": {
"type": "INDIVIDUAL",
"name": "John",
"lastname": "Doe",
"document": {
"id": "37895247",
"type": "DNI"
},
"email": "[email protected]",
"phone": {
"countryCode": "1",
"areaCode": "11",
"number": "98789632"
},
"address": null,
"birthdate": null,
"nationality": null
},
"intermediaries": [],
"wireInstructions": null,
"date": {
"creationDate": "2024-05-19T19:02:44.018+00:00",
"processedDate": "2024-05-19T19:02:44.799618",
"expirationDate": "0001-01-01T00:00:00"
},
"card": {
"token": "N66a0BVHGJY/oCwOyl/CbxIJ5DmCINWeir9PY9gxVGI=",
"bin": "402670",
"brand": "VISA",
"country": "RS",
"name": "John Doe",
"last4": "3263",
"expirationYear": 2029,
"expirationMonth": 9
},
"errors": []
}curl --request POST \
--url https://api.stage.localpayment.com/api/payout/ \
--header 'Authorization: Bearer <your_access_token>' \
--header 'Content-Type: application/json' \
--data '[{
"externalId": "3b7e91a0-2c4d-4f83-a1b2-d05143e2238a",
"country": "ARG",
"currency": "ARS",
"amount": 10000,
"accountNumber": "{{accountNumber}}",
"exchangeRateToken": "8f2d14b3-c4ea-4912-b7a1-922cd1e255fb",
"paymentMethod": {
"type": "BankTransfer",
"code": "1005",
"flow": "DIRECT"
}
}]'Show the exchange rate before checkout
If you're building a checkout and want to display the exchange rate to your user before they confirm the payment, this is the flow:
- The user selects an amount and currency.
- Your backend calls Currency Exchange Quote API and receives the rate in the
exchangeRateTokenparameter. - Your frontend shows: "You will pay 10,000 ARS ≈ 8.37 USD (rate: 0.000837)"
- User confirms.
- Your backend submits the payin with the
exchangeRateTokento apply the locked rate.
This guarantees that the rate your user saw is the rate applied to the transaction as long as you submit before the token's expirationDate.
Design tip:
Show the
expirationDatein your UI as a countdown (e.g. "Rate valid for 8 hours"). This sets the right expectation and reduces support tickets when a rate changes between sessions.
Updated 21 days ago
