SEP-38: Quotes
Request exchange rates and lock in firm quotes for GHS/USDC conversions using the SEP-38 Anchor RFQ API.
SEP-38 provides a Request for Quote (RFQ) API that lets you discover available asset pairs, check indicative prices, and lock in firm quotes before initiating a deposit or withdrawal. Using quotes ensures the customer knows exactly how much they'll pay or receive.
Endpoints
| Method | Path | Description |
|---|---|---|
| GET | /sep38/prices | List available asset pairs and indicative rates |
| GET | /sep38/price | Get an indicative price for a specific pair |
| POST | /sep38/quote | Create a firm quote with a locked rate |
| GET | /sep38/quote/:id | Retrieve an existing quote |
All endpoints require a valid SEP-10 JWT token.
Asset identifiers
SEP-38 uses standardized asset identifiers:
| Asset | Identifier |
|---|---|
| USDC on Stellar | stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5 |
| Ghana Cedis | iso4217:GHS |
GET /prices — List available pairs
curl -X GET "https://<your-anchor-domain>/sep38/prices?\
sell_asset=iso4217:GHS&\
sell_amount=100" \
-H "Authorization: Bearer <sep10_jwt_token>"import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
// Note: The wallet SDK does not have SEP-38 built in.
// Use fetch for quote operations until SDK support is added.
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
// Authenticate
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Fetch prices via SEP-38 (raw fetch — not yet in wallet SDK)
const toml = await anchor.getInfo();
const quoteServer = toml.anchorQuoteServer;
const params = new URLSearchParams({
sell_asset: 'iso4217:GHS',
sell_amount: '100',
});
const res = await fetch(`${quoteServer}/sep38/prices?${params}`, {
headers: { Authorization: `Bearer ${authToken}` },
});
const data = await res.json();
console.log("Available buy assets:", data.buy_assets);Response:
{
"price": "15.38",
"sell_amount": "100.00",
"buy_amount": "6.50",
"fee": {
"total": "0.10",
"asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
}
}Indicative prices are for display purposes. They are not guaranteed and may change. Use POST /quote to lock in a firm rate.
POST /quote — Create a firm quote
Lock in a rate for a specific conversion. Firm quotes have an expiration time.
Deposit quote (GHS → USDC)
curl -X POST "https://<your-anchor-domain>/sep38/quote" \
-H "Authorization: Bearer <sep10_jwt_token>" \
-H "Content-Type: application/json" \
-d '{
"sell_asset": "iso4217:GHS",
"buy_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"sell_amount": "100",
"context": "sep6"
}'import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
// Note: SEP-38 is not yet built into the wallet SDK. Use fetch.
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
const toml = await anchor.getInfo();
const quoteServer = toml.anchorQuoteServer;
const res = await fetch(`${quoteServer}/sep38/quote`, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
sell_asset: 'iso4217:GHS',
buy_asset: 'stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
sell_amount: '100',
context: 'sep6',
}),
});
const quote = await res.json();
console.log(`Quote ID: ${quote.id}, expires: ${quote.expires_at}`);Response:
{
"id": "quote_a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d",
"expires_at": "2026-08-05T01:49:15Z",
"price": "15.38",
"sell_asset": "iso4217:GHS",
"sell_amount": "100.00",
"buy_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"buy_amount": "6.50",
"fee": {
"total": "0.10",
"asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
}
}Withdrawal quote (USDC → GHS)
curl -X POST "https://<your-anchor-domain>/sep38/quote" \
-H "Authorization: Bearer <sep10_jwt_token>" \
-H "Content-Type: application/json" \
-d '{
"sell_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"buy_asset": "iso4217:GHS",
"sell_amount": "6.5",
"context": "sep6"
}'import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
// Note: SEP-38 is not yet built into the wallet SDK. Use fetch.
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
const toml = await anchor.getInfo();
const quoteServer = toml.anchorQuoteServer;
const res = await fetch(`${quoteServer}/sep38/quote`, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
sell_asset: 'stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
buy_asset: 'iso4217:GHS',
sell_amount: '6.5',
context: 'sep6',
}),
});
const quote = await res.json();
console.log(`Quote ID: ${quote.id}, you get: ${quote.buy_amount} GHS`);Response:
{
"id": "quote_b2c3d4e5-f6a7-8b9c-0d1e-2f3a4b5c6d7e",
"expires_at": "2026-08-05T01:49:15Z",
"price": "0.065",
"sell_asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5",
"sell_amount": "6.50",
"buy_asset": "iso4217:GHS",
"buy_amount": "100.00",
"fee": {
"total": "0.10",
"asset": "stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5"
}
}Using a quote with SEP-6
Pass the quote_id when initiating a deposit or withdrawal to use the locked rate:
curl -X GET "https://<your-anchor-domain>/sep6/deposit?\
asset_code=USDC&\
account=GCEXAMPLE4KEYPAIR7HERE2REPLACE5WITH5YOUR5ACTUAL5STELLAR5KEY&\
amount=6.5&\
funding_method=mobile&\
quote_id=quote_a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d" \
-H "Authorization: Bearer <sep10_jwt_token>"import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
const wallet = Wallet.TestNet();
const anchor = wallet.anchor({ homeDomain: '<your-anchor-domain>' });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Use the quote_id with SEP-6 deposit via the wallet SDK
const sep6 = anchor.sep6();
const deposit = await sep6.deposit({
authToken,
params: {
asset_code: 'USDC',
account: accountKp.publicKey,
amount: '6.5',
funding_method: 'mobile',
quote_id: 'quote_a1b2c3d4-e5f6-7a8b-9c0d-1e2f3a4b5c6d',
},
});
console.log("Deposit with locked quote:", deposit.id);Quotes expire. If the quote has expired when you initiate the transaction, the anchor will return a 400 error. Create a new quote and retry.
TypeScript example
import { Wallet, Keypair } from '@stellar/typescript-wallet-sdk';
// Note: SEP-38 quotes are not yet built into the wallet SDK.
// Use the wallet SDK for authentication, then fetch for quotes.
const wallet = Wallet.TestNet();
const ANCHOR_HOME_DOMAIN = '<your-anchor-domain>';
const anchor = wallet.anchor({ homeDomain: ANCHOR_HOME_DOMAIN });
const accountKp = Keypair.fromSecret('SCZANGBA5YHTNYVVV3C7CAZMCLXPJLNS2YFGXDNASLFTGBPFMRKCY6ML');
// Authenticate using wallet SDK
const sep10 = await anchor.sep10();
const authToken = await sep10.authenticate({ accountKp });
// Get anchor info to find quote server URL
const toml = await anchor.getInfo();
const quoteServer = toml.anchorQuoteServer;
interface Quote {
id: string;
expires_at: string;
price: string;
sell_asset: string;
sell_amount: string;
buy_asset: string;
buy_amount: string;
fee: { total: string; asset: string };
}
async function getIndicativePrice(
sellAsset: string,
buyAsset: string,
sellAmount: string
) {
const params = new URLSearchParams({ sell_asset: sellAsset, buy_asset: buyAsset, sell_amount: sellAmount });
const res = await fetch(`${quoteServer}/sep38/price?${params}`, {
headers: { Authorization: `Bearer ${authToken}` },
});
return res.json();
}
async function createQuote(
sellAsset: string,
buyAsset: string,
sellAmount: string
): Promise<Quote> {
const res = await fetch(`${quoteServer}/sep38/quote`, {
method: 'POST',
headers: {
Authorization: `Bearer ${authToken}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
sell_asset: sellAsset,
buy_asset: buyAsset,
sell_amount: sellAmount,
context: 'sep6',
}),
});
if (!res.ok) {
const error = await res.json();
throw new Error(`Quote failed: ${error.error}`);
}
return res.json();
}
// Usage: Get a firm quote for depositing 100 GHS
const quote = await createQuote(
'iso4217:GHS',
'stellar:USDC:GBBD47IF6LWK7P7MDEVSCWR7DPUWV3NY3DTQEVFL4NAT4AQH3ZLLFLA5',
'100'
);
console.log(`Quote ${quote.id}: ${quote.sell_amount} GHS → ${quote.buy_amount} USDC`);
console.log(`Rate: 1 USDC = ${quote.price} GHS`);
console.log(`Expires: ${quote.expires_at}`);
// Use the quote with SEP-6 deposit via wallet SDK
const sep6 = anchor.sep6();
const deposit = await sep6.deposit({
authToken,
params: {
asset_code: 'USDC',
account: accountKp.publicKey,
amount: quote.buy_amount,
funding_method: 'mobile',
quote_id: quote.id,
},
});
console.log("Deposit with locked quote:", deposit.id);Quote parameters
| Parameter | Required | Description |
|---|---|---|
sell_asset | Yes | Asset identifier being sold |
buy_asset | Yes | Asset identifier being bought |
sell_amount | One of | Amount of sell asset (mutually exclusive with buy_amount) |
buy_amount | One of | Amount of buy asset (mutually exclusive with sell_amount) |
context | Yes | Context for the quote — sep6 or sep24 |
Error responses
| Status | Error | Meaning |
|---|---|---|
| 400 | invalid_asset | Asset identifier not recognized |
| 400 | invalid_amount | Amount outside supported range |
| 400 | quote_expired | Referenced quote has expired |
| 404 | quote_not_found | Quote ID does not exist |
| 500 | internal_error | Anchor-side error |