Quote a currency conversion
Prices a conversion for a payment to an international-fx account denominated in a currency other than USD, and returns a short-lived quoteToken that locks the rate.
Pass the token as fxQuoteToken on POST /payments to be charged exactly what was quoted. The token is optional — omit it and the payment is priced again at creation time, at whatever rate then applies.
Fees are priced separately by POST /tools/fee-calculator; the two are independent and can be called in either order.
const options = {
method: 'POST',
headers: {
'Melio-Entity-Id': '<melio-entity-id>',
'api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
receivingAccountId: 'acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7',
amount: 100000,
currency: 'EUR',
purpose: 'payment for consulting services'
})
};
fetch('https://api.melio.com/v2/tools/fx-quote', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.melio.com/v2/tools/fx-quote"
payload = {
"receivingAccountId": "acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7",
"amount": 100000,
"currency": "EUR",
"purpose": "payment for consulting services"
}
headers = {
"Melio-Entity-Id": "<melio-entity-id>",
"api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)curl --request POST \
--url https://api.melio.com/v2/tools/fx-quote \
--header 'Content-Type: application/json' \
--header 'Melio-Entity-Id: <melio-entity-id>' \
--header 'api-key: <api-key>' \
--data '
{
"receivingAccountId": "acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7",
"amount": 100000,
"currency": "EUR",
"purpose": "payment for consulting services"
}
'HttpResponse<String> response = Unirest.post("https://api.melio.com/v2/tools/fx-quote")
.header("Melio-Entity-Id", "<melio-entity-id>")
.header("api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"receivingAccountId\": \"acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7\",\n \"amount\": 100000,\n \"currency\": \"EUR\",\n \"purpose\": \"payment for consulting services\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.melio.com/v2/tools/fx-quote")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Melio-Entity-Id"] = '<melio-entity-id>'
request["api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"receivingAccountId\": \"acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7\",\n \"amount\": 100000,\n \"currency\": \"EUR\",\n \"purpose\": \"payment for consulting services\"\n}"
response = http.request(request)
puts response.read_bodypackage main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.melio.com/v2/tools/fx-quote"
payload := strings.NewReader("{\n \"receivingAccountId\": \"acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7\",\n \"amount\": 100000,\n \"currency\": \"EUR\",\n \"purpose\": \"payment for consulting services\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Melio-Entity-Id", "<melio-entity-id>")
req.Header.Add("api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"currency": "EUR",
"foreignAmount": 100000,
"amount": 110250,
"usdToForeignRate": 0.907,
"midMarketRate": 0.9125,
"quoteToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb3JlaWduQ3VycmVuY3kiOiJFVVIifQ.sig",
"expiresAt": "2026-09-06T12:34:56Z"
}{
"error": {
"type": "invalid_request_error",
"code": "VALIDATION_ERROR",
"message": "<string>",
"details": {}
}
}{
"error": {
"type": "invalid_request_error",
"code": "VALIDATION_ERROR",
"message": "<string>",
"details": {}
}
}Headers
Body
Only accounts that actually convert currency can be quoted: an international-fx account denominated in something other than USD. Anything else — a domestic account, a USD-denominated international account, or international-gusd, which is dollar-denominated — is rejected with 400.
Response
The priced conversion and the token that locks it.
A priced currency conversion. foreignAmount is what the counterparty receives and amount is what the entity is debited, both in minor units of their own currency and both excluding fees.
Opaque, short-lived token locking this rate. Pass it as fxQuoteToken on POST /payments, for a payment of this amount in this currency — the token is checked against both, so it cannot be spent on a payment it was not quoted for. Treat it as opaque; its format is not part of this contract.
const options = {
method: 'POST',
headers: {
'Melio-Entity-Id': '<melio-entity-id>',
'api-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
receivingAccountId: 'acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7',
amount: 100000,
currency: 'EUR',
purpose: 'payment for consulting services'
})
};
fetch('https://api.melio.com/v2/tools/fx-quote', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.melio.com/v2/tools/fx-quote"
payload = {
"receivingAccountId": "acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7",
"amount": 100000,
"currency": "EUR",
"purpose": "payment for consulting services"
}
headers = {
"Melio-Entity-Id": "<melio-entity-id>",
"api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)curl --request POST \
--url https://api.melio.com/v2/tools/fx-quote \
--header 'Content-Type: application/json' \
--header 'Melio-Entity-Id: <melio-entity-id>' \
--header 'api-key: <api-key>' \
--data '
{
"receivingAccountId": "acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7",
"amount": 100000,
"currency": "EUR",
"purpose": "payment for consulting services"
}
'HttpResponse<String> response = Unirest.post("https://api.melio.com/v2/tools/fx-quote")
.header("Melio-Entity-Id", "<melio-entity-id>")
.header("api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"receivingAccountId\": \"acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7\",\n \"amount\": 100000,\n \"currency\": \"EUR\",\n \"purpose\": \"payment for consulting services\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.melio.com/v2/tools/fx-quote")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Melio-Entity-Id"] = '<melio-entity-id>'
request["api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"receivingAccountId\": \"acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7\",\n \"amount\": 100000,\n \"currency\": \"EUR\",\n \"purpose\": \"payment for consulting services\"\n}"
response = http.request(request)
puts response.read_bodypackage main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.melio.com/v2/tools/fx-quote"
payload := strings.NewReader("{\n \"receivingAccountId\": \"acct_2a4f9c31-77ad-4c1e-8b52-6d3f0a91c4e7\",\n \"amount\": 100000,\n \"currency\": \"EUR\",\n \"purpose\": \"payment for consulting services\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Melio-Entity-Id", "<melio-entity-id>")
req.Header.Add("api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}{
"currency": "EUR",
"foreignAmount": 100000,
"amount": 110250,
"usdToForeignRate": 0.907,
"midMarketRate": 0.9125,
"quoteToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb3JlaWduQ3VycmVuY3kiOiJFVVIifQ.sig",
"expiresAt": "2026-09-06T12:34:56Z"
}{
"error": {
"type": "invalid_request_error",
"code": "VALIDATION_ERROR",
"message": "<string>",
"details": {}
}
}{
"error": {
"type": "invalid_request_error",
"code": "VALIDATION_ERROR",
"message": "<string>",
"details": {}
}
}