_gammadocs
API Reference

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. Add sharesAmount to get the same amount-specific withdrawal economics used by the app. Requires a read-scope API key; wallet binding and consumer vault restrictions apply to the preview too.

Param Description
wallet Wallet pubkey (required).
sharesAmount Optional positive integer decimal string in raw share units, identical to the amount used by withdrawal POST. Bounded to u64 and the wallet's current share balance. Omit for status-only polling.
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 in display share units, or 0 (legacy field).
estimatedUsdcAmount Estimated value of pending shares in the vault's asset units, including SOL for SOL vaults (legacy field name).
canClaimNow Whether the receipt is claimable on-chain now.
createdAt Latest verified queued-withdrawal request's confirmed block time (ISO 8601), or null if no shares are pending or request history is unavailable. The receipt's NAV ordering floor is not a request timestamp.
estimate { kind, band, closeSlippage, asOf }, or null. With sharesAmount, describes that prospective withdrawal; otherwise describes pending timing and has no amount-specific slippage quote.
progress Live staging progress, or null.
preview Present only when sharesAmount is supplied. Amount-bound advisory economics described below.

Preview before withdrawing

curl "https://app.gma.fi/api/vault/VAULT_PUBKEY/withdraw?wallet=YOUR_WALLET_PUBKEY&sharesAmount=50000000" \
  -H "Authorization: Bearer YOUR_API_KEY"

50000000 means raw shares, not 50 million SOL lamports or a USD value. Convert display shares using the vault's share decimals. Send the same raw string as sharesAmount to POST when the user chooses to proceed. The API does not simulate a deposit for requests above the wallet's balance.

Response data.preview:

Field Description
advisory Always true. No transaction is built and no capacity is reserved.
asOf Estimate-generation time (ISO 8601). Underlying liquidity/provider reads may use the app's short-lived caches; this is not an atomic blockchain snapshot or expiry guarantee.
sharesAmountRaw, walletSharesRaw Requested and owned raw shares as exact decimal strings.
asset { mint, symbol, decimals } identifying the denomination of all asset amounts.
sharePrice, navRaw, totalSharesRaw Current raw asset/share price and exact raw vault NAV/supply used for gross sizing.
withdrawalPolicy Live retained-fee and net-outflow-cap policy.
withdrawalLimits, limitBreach Current hourly/daily capacity and the first breached window, or null for no breach. Limits are advisory and rechecked when building/executing.
withdrawalEstimate Exact grossAssetsRaw, feeAssetsRaw, netAssetsRaw strings and corresponding display amounts before unwind costs, plus fee/waiver metadata. The final-holder waiver requires ownership of the exact live supply.
blockedReasons Current receipt/cap blockers: pending-withdrawal, claim-required, hourly-capacity-exceeded, or daily-capacity-exceeded. An empty array does not guarantee execution; NAV freshness and other transaction checks still apply.
estimate Full shared app estimate: arrival kind (instant, queued, queued_bridge), measured/fallback band, closeSlippage, and asOf.
quoteStatus complete when proceeds can be estimated; unavailable for missing, incomplete, or unsupported unwind quotes.
costs The app's cost breakdown below, or null when the quote is unavailable.
costBasisAssets Acquisition cost allocated to the selected shares, or null when accounting is provisional/unavailable or cannot be represented safely.
estimatedNetProfitAssets Estimated proceeds minus personal acquisition cost, or null when costs or basis are unavailable.

preview.costs contains display amounts in the vault's asset, not raw integers:

Field Meaning
estimatedReceivedAssets Estimated amount received after the user's share of NAV loss and the retained withdrawal fee.
totalUserCostAssets Gross claim minus estimated proceeds.
estimatedFeeAssets Retained withdrawal fee applied after the estimated NAV loss.
estimatedUserNavImpactAssets This holder's attributed share of unwind loss.
estimatedVaultUnwindCostAssets Total loss from the vault unwind; do not subtract it again from this holder's proceeds.
estimatedRemainingHolderImpactAssets Unwind loss attributed to the remaining holders.
estimatedFeeCoverageShortfallAssets, estimatedFeeCoverageSurplusAssets Remaining-holder loss relative to retained fees. A surplus stays in the vault; it is not refunded to the withdrawing wallet.
projectedOwnershipFraction Fraction used to attribute unwind loss; 0 for a cash-only preview with no unwind.

estimate.closeSlippage retains the app's model scope, completeness/provider details, estimated basis points, and any unavailability reason. Its estimatedCostAssets is the vault-level unwind loss. Use preview.costs for the user's costs and proceeds. For example, a 100 SOL claim owning 10% of a vault with a 2 SOL unwind loss incurs 0.2 SOL of NAV impact; a 10 bps retained fee on 99.8 SOL is 0.0998 SOL, producing an estimated 99.7002 SOL payout. This is an illustrative calculation, not a live quote or a fixed fee policy.

Render expected proceeds only when quoteStatus === "complete" and costs is non-null. Otherwise show the quote as unavailable; withdrawalEstimate.netAssets does not include unquoted unwind costs. Missing cost basis only suppresses profit, not an otherwise complete proceeds estimate. Network fees are excluded. All display amounts are advisory floating-point values; use exact raw strings for the withdrawal request. Refresh before submission. Execution independently checks balances, policies, capacity and market conditions and re-quotes any trades; the preview is neither a slippage tolerance nor a guaranteed minimum output.

Invalid/duplicate, zero, fractional, out-of-u64, or over-balance sharesAmount returns 400. Missing required live balance/NAV/policy/limit data returns 503. Provider quote failure returns 200 with quoteStatus: "unavailable" and costs: null, preserving fee, capacity and receipt information.

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 Deprecated; always null. Preparation does not reserve capacity. Withdrawal caps are enforced on-chain when the signed transaction executes.

When claiming, the reservation and estimate fields are null; the message states the approximate amount to claim.

Withdrawal capacity errors

Preparation checks capacity without reserving it. Another withdrawal can consume capacity before your signed transaction executes. The program can return:

Code Error Recovery
6020 HourlyWithdrawalCapExceeded Refresh the quote and reduce the amount, or wait for capacity to become available.
6021 DailyWithdrawalCapExceeded Refresh the quote and reduce the amount, or wait for capacity to become available.

Signing, submitting, and recording

  1. Deserialize the base64 into a VersionedTransaction.
  2. Simulate (recommended) before signing.
  3. Sign with the wallet.
  4. Submit and confirm.
  5. Record the confirmed signature with POST /api/history. Omit the deprecated withdrawal_reservation_id for newly prepared withdrawals.

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 before recording the claim; a claim recorded first returns 409. See POST /api/history.

Next: Public endpoints