Create your first hedge
After sharing your historical business transactions and creating your customers, you can start hedging transactions. At Grain, hedging is a two steps process - Get quote, and then Accept quote, as follows
1. Get quote
First, get a quote for your cross currency business transaction. The quote can be used to display a product price to your customers in a local currency. Grain’s offers 2 methods for pulling the quotes:
a. Single quote
Pull an online quote on demand for a specific due date, with a default expiration of 5 minutes. Get the local currency price using the get quote endpoint:
- cURL
- JavaScript
- Python
- Java
- C#
curl --request POST \
--url https://api.grainfinance.co/v1/customers/{customerId}/hedges/quote \
--header "Content-Type: application/json" \
--header 'Authorization: Basic CLIENT_ID:CLIENT_SECRET' \
--header "'X-Customer-IP': IP_OF_YOUR_CUSTOMER" \
--data '{
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}"
}'
const url = 'https://api.grainfinance.co/v1/customers/{customerId}/hedges/quote';
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic CLIENT_ID:CLIENT_SECRET',
'X-Customer-IP': IP_OF_YOUR_CUSTOMER
},
body: JSON.stringify({
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}"
})
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
import requests
url = 'https://api.grainfinance.co/v1/customers/{customerId}/hedges/quote'
payload = {
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}"
}
headers = {
'Content-Type': 'application/json',
'X-Customer-IP': IP_OF_YOUR_CUSTOMER
}
response = requests.post(
url,
headers=headers,
json=payload
)
data = response.json()
AsyncHttpClient client = new DefaultAsyncHttpClient();
client.prepare("POST", "https://api.grainfinance.co/v1/customers/{customerId}/hedges/quote")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET")
.setHeader("'X-Customer-IP'", "IP_OF_YOUR_CUSTOMER")
.setBody("{
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}"
}")
.execute()
.toCompletableFuture()
.thenAccept(System.out::println)
.join();
client.close();
using RestSharp;
var options = new RestClientOptions("https://api.grainfinance.co/v1/customers/{customerId}/hedges/quote");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET");
request.AddHeader("'X-Customer-IP'", "IP_OF_YOUR_CUSTOMER");
request.AddParameter("data", "{
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}"
}");
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
b. Offline Quotes
Retrieve quotes for all operational currencies and supported tenors at the same call. You’ll receive a complete quote table, which allows offline quote selection based on each transaction’s currency pair, due date, and corresponding tenor. This approach eliminates the need to call Grain individually for each transaction, and reduces system load by multiple calls. The table’s expiration time is configurable, with a default of 1 hour. Retrieve bulk offline quotes using the offline quote endpoint:
- cURL
- JavaScript
- Python
- Java
- C#
curl --request GET \
--url https://api.grainfinance.co/v1/offline-rates \
--header "Content-Type: application/json" \
--header 'Authorization: Basic CLIENT_ID:CLIENT_SECRET'
const url = 'https://api.grainfinance.co/v1/offline-rates';
const options = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic CLIENT_ID:CLIENT_SECRET'
}
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
import requests
url = 'https://api.grainfinance.co/v1/offline-rates'
headers = {
'Content-Type': 'application/json'
}
response = requests.get(
url,
headers=headers
)
data = response.json()
AsyncHttpClient client = new DefaultAsyncHttpClient();
client.prepare("GET", "https://api.grainfinance.co/v1/offline-rates")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET")
.execute()
.toCompletableFuture()
.thenAccept(System.out::println)
.join();
client.close();
using RestSharp;
var options = new RestClientOptions("https://api.grainfinance.co/v1/offline-rates");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET");
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
2. Accept quote
In this step, you will accept a quote you received in the previous step and create the hedge. Identically to the get quote step, there are also two methods for accepting a quote:
a. Accept quote - if you used the "Get Single Quote" call, send the quote ID received in that call (as hedgeProposalId) using the accept quote endpoint:
- cURL
- JavaScript
- Python
- Java
- C#
curl --request POST \
--url https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-quote \
--header "Content-Type: application/json" \
--header 'Authorization: Basic CLIENT_ID:CLIENT_SECRET' \
--header "'X-Customer-IP': IP_OF_YOUR_CUSTOMER" \
--data '{
"hedgeProposalId": "{hedgeProposalId}",
"transactionId": "{transactionId}"
}'
const url = 'https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-quote';
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic CLIENT_ID:CLIENT_SECRET',
'X-Customer-IP': IP_OF_YOUR_CUSTOMER
},
body: JSON.stringify({
"hedgeProposalId": "{hedgeProposalId}",
"transactionId": "{transactionId}"
})
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
import requests
url = 'https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-quote'
payload = {
"hedgeProposalId": "{hedgeProposalId}",
"transactionId": "{transactionId}"
}
headers = {
'Content-Type': 'application/json',
'X-Customer-IP': IP_OF_YOUR_CUSTOMER
}
response = requests.post(
url,
headers=headers,
json=payload
)
data = response.json()
AsyncHttpClient client = new DefaultAsyncHttpClient();
client.prepare("POST", "https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-quote")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET")
.setHeader("'X-Customer-IP'", "IP_OF_YOUR_CUSTOMER")
.setBody("{
"hedgeProposalId": "{hedgeProposalId}",
"transactionId": "{transactionId}"
}")
.execute()
.toCompletableFuture()
.thenAccept(System.out::println)
.join();
client.close();
using RestSharp;
var options = new RestClientOptions("https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-quote");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET");
request.AddHeader("'X-Customer-IP'", "IP_OF_YOUR_CUSTOMER");
request.AddParameter("data", "{
"hedgeProposalId": "{hedgeProposalId}",
"transactionId": "{transactionId}"
}");
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
b. Accept offline quote - in case you used the offline option to get the quotes, send the calculated rate and its revision, along with the from and to currencies, the amount in the to currency, and the end date. Use the accept offline quote endpoint to submit all the details and create the hedge:
- cURL
- JavaScript
- Python
- Java
- C#
curl --request POST \
--url https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-offline-quote \
--header "Content-Type: application/json" \
--header 'Authorization: Basic CLIENT_ID:CLIENT_SECRET' \
--header "'X-Customer-IP': IP_OF_YOUR_CUSTOMER" \
--data '{
"revision": "{revision}",
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}",
"rate": "{rate}"
}'
const url = 'https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-offline-quote';
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic CLIENT_ID:CLIENT_SECRET',
'X-Customer-IP': IP_OF_YOUR_CUSTOMER
},
body: JSON.stringify({
"revision": "{revision}",
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}",
"rate": "{rate}"
})
};
try {
const response = await fetch(url, options);
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
import requests
url = 'https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-offline-quote'
payload = {
"revision": "{revision}",
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}",
"rate": "{rate}"
}
headers = {
'Content-Type': 'application/json',
'X-Customer-IP': IP_OF_YOUR_CUSTOMER
}
response = requests.post(
url,
headers=headers,
json=payload
)
data = response.json()
AsyncHttpClient client = new DefaultAsyncHttpClient();
client.prepare("POST", "https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-offline-quote")
.setHeader("Content-Type", "application/json")
.setHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET")
.setHeader("'X-Customer-IP'", "IP_OF_YOUR_CUSTOMER")
.setBody("{
"revision": "{revision}",
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}",
"rate": "{rate}"
}")
.execute()
.toCompletableFuture()
.thenAccept(System.out::println)
.join();
client.close();
using RestSharp;
var options = new RestClientOptions("https://api.grainfinance.co/v1/customers/{customerId}/hedges/accept-offline-quote");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Basic CLIENT_ID:CLIENT_SECRET");
request.AddHeader("'X-Customer-IP'", "IP_OF_YOUR_CUSTOMER");
request.AddParameter("data", "{
"revision": "{revision}",
"fromCurrency": "{fromCurrency}",
"toCurrency": "{toCurrency}",
"toCurrencyAmount": "{toCurrencyAmount}",
"endAt": "{endAt}",
"rate": "{rate}"
}");
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);