curl -X POST https://grail-stack-dev.onrender.com/v1/buy \
-H "x-api-key: grail_partner_<hex>" \
-H "Content-Type: application/json" \
-d '{
"grail_user_id": "gu_6b60956e-a8ee-4de2-8128-04c7fdf633c3",
"usdc_amount": 100,
"slippage_bps": 50
}'
{
"trade_id": "trd_4e7a1b8f-9c32-4a91-b3e6-7f12a8d4c5e9",
"side": "buy",
"quote": {
"usdc_amount": 100,
"gold_amount": 0.0205,
"price_per_troy_oz": 4872.84,
"fee_bps": 50,
"fee_usd": 0.50,
"min_gold_out": 0.0204
},
"partially_signed_transaction": "AQAAAAABAAEC...<base64>..."
}
Trades
Quote Buy
Stateless quote for buying $GOLD with USDC. Returns a partially-signed Solana transaction to co-sign and submit.
POST
/
v1
/
buy
curl -X POST https://grail-stack-dev.onrender.com/v1/buy \
-H "x-api-key: grail_partner_<hex>" \
-H "Content-Type: application/json" \
-d '{
"grail_user_id": "gu_6b60956e-a8ee-4de2-8128-04c7fdf633c3",
"usdc_amount": 100,
"slippage_bps": 50
}'
{
"trade_id": "trd_4e7a1b8f-9c32-4a91-b3e6-7f12a8d4c5e9",
"side": "buy",
"quote": {
"usdc_amount": 100,
"gold_amount": 0.0205,
"price_per_troy_oz": 4872.84,
"fee_bps": 50,
"fee_usd": 0.50,
"min_gold_out": 0.0204
},
"partially_signed_transaction": "AQAAAAABAAEC...<base64>..."
}
Overview
Builds a buy transaction (USDC →$GOLD) and returns it partially-signed by GRAIL. The client must co-sign with the partner wallet and the user wallet, then either call Submit Buy or broadcast directly to a Solana RPC.
This endpoint is stateless — no database row is created at quote time. The Trade row is written by the indexer once the transaction confirms on-chain (confirmed or failed).
The partial-signed transaction expires in ~60 seconds (Solana
recentBlockhash TTL). If you take too long to co-sign and submit, you’ll get broadcast_failed: Blockhash not found. Re-quote.Headers
string
required
A valid
PARTNER scope key.Request Body
string
required
GRAIL user ID (prefixed
gu_). User must belong to the authenticated partner, be active, and have kyc_level: "full".number
required
USDC the user will spend, in human decimal (e.g.,
100 = 100 USDC). Must be positive.integer
Slippage tolerance in basis points. Default
50 (0.5%). Ignored if min_gold_out is provided.number
Absolute minimum
$GOLD to receive (human decimal). If supplied, overrides slippage_bps. If omitted, computed as quoted_gold * (10000 - slippage_bps) / 10000.Response
string
Trade identifier, prefixed
trd_. Use with Submit Buy and Get Trade.string
Always
"buy".object
Show properties
Show properties
number
Input USDC (echo of request).
number
Expected
$GOLD output at quote-time spot price (pre-slippage).number
Gold spot price in USD per troy ounce at quote time.
integer
Fee rate applied in basis points (derived from the partner’s IntegratorV2 on-chain config).
number
Fee in USDC deducted from the input before swap.
number
Minimum
$GOLD the tx will accept — slippage floor.string
Base64-encoded Solana transaction, already signed by GRAIL. Co-sign with partner + user and submit.
Errors
| HTTP | error | When |
|---|---|---|
| 400 | invalid_request | Missing or non-positive usdc_amount, missing grail_user_id |
| 400 | kyc_level_insufficient | User’s KYC level is not full |
| 400 | onchain_config_missing | Partner’s on-chain config hasn’t been set up yet. Contact ORO. |
| 400 | wallet_missing | Partner has no registered wallet |
| 403 | partner_mismatch | User belongs to a different partner |
| 403 | user_suspended | User status is suspended |
| 404 | user_not_found | No user with the given grail_user_id |
| 503 | pricing_unavailable | Gold price oracle unreachable or returned stale data |
curl -X POST https://grail-stack-dev.onrender.com/v1/buy \
-H "x-api-key: grail_partner_<hex>" \
-H "Content-Type: application/json" \
-d '{
"grail_user_id": "gu_6b60956e-a8ee-4de2-8128-04c7fdf633c3",
"usdc_amount": 100,
"slippage_bps": 50
}'
{
"trade_id": "trd_4e7a1b8f-9c32-4a91-b3e6-7f12a8d4c5e9",
"side": "buy",
"quote": {
"usdc_amount": 100,
"gold_amount": 0.0205,
"price_per_troy_oz": 4872.84,
"fee_bps": 50,
"fee_usd": 0.50,
"min_gold_out": 0.0204
},
"partially_signed_transaction": "AQAAAAABAAEC...<base64>..."
}
