Transactions
Build unsigned deposit and withdraw transactions, check withdrawal status, and sign, submit, and record them.
The deposit and withdraw endpoints return an unsigned, base64-encoded VersionedTransaction that your wallet signs and submits. They require a write-scope key. The withdraw-status read requires read. After a transaction confirms, record it with POST /api/history so the activity feed updates immediately.
POST /api/vault/{vault_id}/deposit
Builds an unsigned deposit transaction.
Body:
| Field | Description |
|---|---|
wallet |
Wallet pubkey (required). |
amount |
Deposit amount in lamports (smallest asset unit). Wins if both are present. |
uiAmount |
Human amount (e.g. 1.5 USDC) — an ergonomic alternative to amount. |
curl -X POST "https://app.gma.fi/api/vault/GPZW7ihHMMfZg5eNDmn376mwVzBKHh867vdWmjvNvYPK/deposit" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"wallet":"YOUR_WALLET_PUBKEY","amount":100000000}'
Response data:
| Field | Description |
|---|---|
transaction |
Base64 VersionedTransaction to sign and submit. |
message |
Human summary of the deposit. |
details |
{ vaultId, vaultName, depositAmount, depositAmountHuman, assetDecimals, estimatedSharesReceived, currentSharePrice }. |
GET /api/vault/{vault_id}/withdraw
Withdrawal status for a wallet.
| Param | Description |
|---|---|
wallet |
Wallet pubkey (required). |
curl "https://app.gma.fi/api/vault/GPZW7ihHMMfZg5eNDmn376mwVzBKHh867vdWmjvNvYPK/withdraw?wallet=YOUR_WALLET_PUBKEY" \
-H "Authorization: Bearer YOUR_API_KEY"
Response data:
| Field | Description |
|---|---|
hasPendingWithdrawal |
Whether a pending withdrawal exists. |
pendingShares |
Pending shares (raw), or 0. |
estimatedUsdcAmount |
Estimated asset value of the pending shares. |
canClaimNow |
Whether the receipt is claimable on-chain now. |
createdAt |
Receipt creation time (oldest pending), or null. |
estimate |
Arrival-time band { kind, band }, or null. |
progress |
Live staging progress, or null. |
POST /api/vault/{vault_id}/withdraw
Initiates a new withdrawal or claims a pending one, chosen from on-chain state (or forced with an explicit action). PUT is an alias for POST.
Body:
| Field | Description |
|---|---|
wallet |
Wallet pubkey (required). |
sharesAmount |
Shares to withdraw, raw units (required when initiating a new withdrawal). |
action |
initiate or claim (optional; auto-detected otherwise). |
curl -X POST "https://app.gma.fi/api/vault/GPZW7ihHMMfZg5eNDmn376mwVzBKHh867vdWmjvNvYPK/withdraw" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"wallet":"YOUR_WALLET_PUBKEY","sharesAmount":50000000}'
Response data always includes action (initiate or claim), the base64 transaction, a message, and details. When initiating, details carries the withdrawal accounting:
| Field | Description |
|---|---|
withdrawalPolicy |
Fee/cap policy in effect. |
withdrawalLimits |
Current net-withdrawal limit state. |
withdrawalEstimate |
Gross/fee/net asset breakdown for the request. |
withdrawalReservation |
{ id, expiresAt } — a capacity reservation. Carry id as withdrawal_reservation_id when you record the confirmed initiate via POST /api/history. |
When claiming, details omits the reservation and estimate; the message states the approximate amount to claim.
Signing, submitting, and recording
- Deserialize the base64 into a
VersionedTransaction. - Simulate (recommended) before signing.
- Sign with the wallet.
- Submit and confirm.
- Record the confirmed signature with
POST /api/history(carrywithdrawal_reservation_idfor a queued initiate).
Blockhash freshness matters: build, sign, and submit promptly. A transaction whose blockhash has expired must be rebuilt (call the endpoint again) rather than retried as-is.
import { Connection, VersionedTransaction } from '@solana/web3.js';
// Your backend keeps the _gamma write key server-side; the browser never sees it.
const PARTNER_API = '/api/gamma';
// 1. Ask your backend for the unsigned transaction.
const res = await fetch(PARTNER_API + '/deposit', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wallet: wallet.publicKey.toBase58(),
amount: 100_000_000, // 100 USDC in lamports (6 decimals)
}),
});
const { data } = await res.json();
// 2. Deserialize the base64 transaction.
const transaction = VersionedTransaction.deserialize(
Buffer.from(data.transaction, 'base64'),
);
// 3. Sign (browser wallet shown; a Keypair works server-side).
const signedTx = await window.solana.signTransaction(transaction);
// 4. Submit and confirm.
const connection = new Connection('https://api.mainnet-beta.solana.com', 'confirmed');
const signature = await connection.sendRawTransaction(signedTx.serialize());
const confirmation = await connection.confirmTransaction(signature, 'confirmed');
if (confirmation.value.err) throw new Error('Transaction failed');
// 5. Record the confirmed signature (idempotent; duplicate === true is success).
await fetch(PARTNER_API + '/history', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
wallet: wallet.publicKey.toBase58(),
vault_id: 'GPZW7ihHMMfZg5eNDmn376mwVzBKHh867vdWmjvNvYPK',
signature,
}),
});
For a queued withdrawal, record the initiate signature (with its reservation id) before recording the claim; a claim recorded first returns 409. See POST /api/history.
Next: Public endpoints