This quickstart walks through generating a quote, creating a Portfolio Wallet from the quote’s positions, funding it via the returned deposit addresses, checking balances and yield, and withdrawing with the signing flow.
Prerequisites
Set your base URL and API token once, then reuse them for every request.
Use sandbox while you build, then switch to production without changing request shapes.
export BASE_URL="https://sandbox.trybraid.xyz"
export BRAID_API_TOKEN="your_api_token"
1. Create a quote with desired parameters
Use quotes to design a strategy with liquidity constraints or minimum APY targets.
Scenario (liquidity-first): you want a wallet where at least 40% of funds are instantly withdrawable, and the remainder can be placed into higher-yield positions that may take longer to unwind. To express that, add a liquidity constraint requiring at least 4000 bps to have maxProcessingTime: PT0H (0 hours).
curl -X POST "$BASE_URL/v2/portfolio-wallets/quote" \
-H "Authorization: Bearer $BRAID_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"requestId": "b7c4ad36-0b77-4b3a-8c9a-1ab6f0b2f98a",
"minApyTargetBps": 500,
"liquidityConstraints": [
{ "maxProcessingTime": "PT0H", "minWeightBps": 4000 }
],
"yieldSourceTypeExclusions": ["deltaNeutralStrategy"]
}'
The response is an array of quote options. Pick the option you want (often quote[0] when constraintsSatisfied is true), then use its strategyConfig.positions to create a wallet.
2. Create a portfolio wallet from the quote
Create a Portfolio Wallet by passing the chosen quote positions as positions. Positions must sum to 10,000 bps (100%).
curl -X POST "$BASE_URL/v2/portfolio-wallets" \
-H "Authorization: Bearer $BRAID_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"requestId": "123e4567-e89b-12d3-a456-426614174000",
"label": "Treasury Portfolio",
"positions": [
{ "positionKey": "tbills", "targetWeightBps": 6000 },
{ "positionKey": "resolvRlp", "targetWeightBps": 4000 }
]
}'
The response includes the wallet id and depositAddresses per chain. Save the wallet id for the remaining steps:
export WALLET_ID="<wallet_id_from_create_response>"
3. Deposit actual funds
Send a stablecoin transfer from your custody to the chain you want to fund.
to: <depositAddresses[chain].address>
chain: arbitrum
token: usdc
amount: 50,000.00
4. Await Deposit Confirmation
Deposits are detected on-chain and then processed. You can track the latest deposit status either by polling the deposits endpoints or by subscribing to webhooks.
Poll (REST):
- List deposits for a wallet:
GET /v2/portfolio-wallets/{id}/deposits
- Fetch a single deposit:
GET /v2/portfolio-wallets/{id}/deposits/{depositId}
Example:
curl -X GET "$BASE_URL/v2/portfolio-wallets/$WALLET_ID/deposits?pageSize=25" \
-H "Authorization: Bearer $BRAID_API_TOKEN"
Webhook events:
portfolio_wallet.deposit.status_changed
Possible deposit statuses (deposit.status):
processing
completed
failed
Per-leg status detail is available in deposit.legStatuses (keys vary by strategy/position). Possible leg statuses:
pending
processing
completed
skipped
failed
5. Fetch the updated balance and yield accrual
Fetch the wallet to get the current balance and yield metrics.
- Current total balance: use
GET /v2/portfolio-wallets/{id} → totalBalanceUsd
- Yield earned:
POST /v2/portfolio-wallets/yield → portfolioWallets[$WALLET_ID].accruedDelta (or global.accruedDelta if you omit portfolioWalletIds)
curl -X GET "$BASE_URL/v2/portfolio-wallets/$WALLET_ID" \
-H "Authorization: Bearer $BRAID_API_TOKEN"
curl -X POST "$BASE_URL/v2/portfolio-wallets/yield" \
-H "Authorization: Bearer $BRAID_API_TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"periodStartIso\": \"2026-01-01T00:00:00Z\",
\"periodEndIso\": \"2026-02-01T00:00:00Z\",
\"portfolioWalletIds\": [\"$WALLET_ID\"]
}"
6. Withdraw (including the signing flow)
Braid uses Turnkey to manage signing flows, but you do not need a relationship with Turnkey to sign approvals.
Initiate a withdrawal. The response includes a turnkeyActivityId if approval is required.
curl -X POST "$BASE_URL/v2/portfolio-wallets/$WALLET_ID/withdraw" \
-H "Authorization: Bearer $BRAID_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"requestId": "df8b7be6-e110-4f6d-9b2d-7c44a5b1f0b0",
"destinationAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44e",
"withdrawalAmount": 65000,
"destinationToken": "usdc",
"destinationChain": "ethereum"
}'
Save the id from the response (this is the withdrawal id used for status checks):
export WITHDRAWAL_ID="<withdrawal_id_from_withdraw_response>"
Customer-side approval example (Turnkey):
Signing keys are provisioned and managed in your Braid Portal account. Ensure you always store signing keys safely as lost or compromised keys could result in lost funds.
import { Turnkey } from "@turnkey/sdk-server";
// Mock keypair for docs only. Replace with your real customer signer key.
const TURNKEY_API_PUBLIC_KEY = "04aa...mock_public_key...ff";
const TURNKEY_API_PRIVATE_KEY = "11bb...mock_private_key...ee";
const TURNKEY_SUB_ORGANIZATION_ID = "your_turnkey_sub_organization_id";
const turnkey = new Turnkey({
apiBaseUrl: "https://api.turnkey.com",
defaultOrganizationId: TURNKEY_SUB_ORGANIZATION_ID,
apiPublicKey: TURNKEY_API_PUBLIC_KEY,
apiPrivateKey: TURNKEY_API_PRIVATE_KEY,
});
const apiClient = turnkey.apiClient();
export async function approveTurnkeyActivity(turnkeyActivityId) {
// 1) Fetch the activity to get its fingerprint
const { activity } = await apiClient.getActivity({
organizationId: TURNKEY_SUB_ORGANIZATION_ID,
activityId: turnkeyActivityId,
});
const fingerprint = activity?.fingerprint;
if (!fingerprint) {
throw new Error("Turnkey activity fingerprint missing");
}
// 2) Approve it (this registers your approval vote in Turnkey)
await apiClient.approveActivity({
type: "ACTIVITY_TYPE_APPROVE_ACTIVITY",
timestampMs: String(Date.now()),
organizationId: TURNKEY_SUB_ORGANIZATION_ID,
parameters: { fingerprint },
});
}
// Usage:
// const { id: withdrawalId, turnkeyActivityId } = withdrawalResponse;
// if (turnkeyActivityId) await approveTurnkeyActivity(turnkeyActivityId);
7. Await Withdrawal Confirmation
After approval (if required), the withdrawal is kicked off automatically. You can track the latest withdrawal status either by polling the withdrawal endpoint or by subscribing to webhooks.
Poll (REST):
curl -X GET "$BASE_URL/v2/portfolio-wallets/$WALLET_ID/withdrawals/$WITHDRAWAL_ID" \
-H "Authorization: Bearer $BRAID_API_TOKEN"
Webhook events:
portfolio_wallet.withdrawal.status_changed
portfolio_wallet.withdrawal.payout.status_changed (per-leg payouts)
Possible withdrawal statuses (withdrawal.status):
pending_approval
created
processing
completed
failed
For more detail, see Get portfolio withdrawal, portfolio-yield-wallets/turnkey-approvals, and the v2 API Reference withdrawal endpoints.