| name | dflow |
| description | Comprehensive guide for building Solana trading apps using DFlow's Swap API. Use when integrating quotes, routing, imperative/declarative swaps, or prediction markets. |
DFlow - Next-Generation Solana Trading Infrastructure
Comprehensive guide for building trading applications on Solana using DFlow's Swap API. Enables token swaps with optimal routing, lower slippage, and access to both spot markets and prediction markets.
Overview
DFlow provides a suite of APIs for next-generation trading on Solana:
- Imperative Swaps - Full control over route selection at signature time
- Declarative Swaps - Intent-based swaps with deferred route optimization
- Trade API - Unified interface for spot and prediction market trading
- Prediction Markets - Infrastructure for trading outcome tokens
Base URL
https://quote-api.dflow.net
Authentication
Most endpoints require an API key via the x-api-key header. Contact hello@dflow.net to obtain credentials.
Quick Start
Imperative Swap (3 Steps)
import { Connection, Keypair, VersionedTransaction } from "@solana/web3.js";
const API_BASE = "https://quote-api.dflow.net";
const API_KEY = process.env.DFLOW_API_KEY;
const SOL = "So11111111111111111111111111111111111111112";
const USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
async function imperativeSwap(keypair: Keypair, connection: Connection) {
const quoteParams = new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000",
slippageBps: "50",
});
const quote = await fetch(`${API_BASE}/quote?${quoteParams}`, {
headers: API_KEY ? { "x-api-key": API_KEY } : {},
}).then(r => r.json());
const swapResponse = await fetch(`${API_BASE}/swap`, {
method: "POST",
headers: {
"content-type": "application/json",
...(API_KEY && { "x-api-key": API_KEY }),
},
body: JSON.stringify({
userPublicKey: keypair.publicKey.toBase58(),
quoteResponse: quote,
dynamicComputeUnitLimit: true,
prioritizationFeeLamports: 150000,
}),
}).then(r => r.json());
const tx = VersionedTransaction.deserialize(
Buffer.from(swapResponse.swapTransaction, "base64")
);
tx.sign([keypair]);
const signature = await connection.sendTransaction(tx);
await connection.confirmTransaction(signature);
return signature;
}
Trade API (Unified - Recommended)
The Trade API provides a single endpoint that handles both sync and async execution:
async function tradeTokens(keypair: Keypair, connection: Connection) {
const orderParams = new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000",
slippageBps: "50",
userPublicKey: keypair.publicKey.toBase58(),
});
const order = await fetch(`${API_BASE}/order?${orderParams}`, {
headers: API_KEY ? { "x-api-key": API_KEY } : {},
}).then(r => r.json());
const tx = VersionedTransaction.deserialize(
Buffer.from(order.transaction, "base64")
);
tx.sign([keypair]);
const signature = await connection.sendTransaction(tx);
if (order.executionMode === "async") {
let status = "pending";
while (status !== "closed" && status !== "failed") {
await new Promise(r => setTimeout(r, 2000));
const statusRes = await fetch(
`${API_BASE}/order-status?signature=${signature}`,
{ headers: API_KEY ? { "x-api-key": API_KEY } : {} }
).then(r => r.json());
status = statusRes.status;
}
} else {
await connection.confirmTransaction(signature);
}
return signature;
}
API Reference
Order API Endpoints
GET /order
Returns a quote and optionally a transaction for spot or prediction market trades.
| Parameter | Required | Description |
|---|
inputMint | Yes | Base58 input token mint |
outputMint | Yes | Base58 output token mint |
amount | Yes | Amount as scaled integer (1 SOL = 1000000000) |
userPublicKey | No | Include to receive signable transaction |
slippageBps | No | Max slippage in basis points or "auto" |
platformFeeBps | No | Platform fee in basis points |
prioritizationFeeLamports | No | "auto", "medium", "high", "veryHigh", or lamport amount |
Response:
{
"outAmount": "150000000",
"minOutAmount": "149250000",
"priceImpactPct": "0.05",
"executionMode": "sync",
"transaction": "base64...",
"computeUnitLimit": 200000,
"lastValidBlockHeight": 123456789,
"routePlan": [...]
}
GET /order-status
Check status of async orders.
| Parameter | Required | Description |
|---|
signature | Yes | Base58 transaction signature |
lastValidBlockHeight | No | Block height for expiry check |
Status Values:
pending - Order submitted, awaiting processing
open - Order opened, awaiting fill
pendingClose - Filled, closing transaction pending
closed - Order completed successfully
expired - Transaction expired before landing
failed - Order execution failed
Imperative Swap Endpoints
GET /quote
Get a quote for an imperative swap.
| Parameter | Required | Description |
|---|
inputMint | Yes | Base58 input mint |
outputMint | Yes | Base58 output mint |
amount | Yes | Input amount (scaled integer) |
slippageBps | No | Slippage tolerance or "auto" |
dexes | No | Comma-separated DEXes to include |
excludeDexes | No | Comma-separated DEXes to exclude |
onlyDirectRoutes | No | Single-leg routes only |
maxRouteLength | No | Max number of route legs |
forJitoBundle | No | Jito bundle compatible routes |
platformFeeBps | No | Platform fee in basis points |
POST /swap
Generate swap transaction from quote.
Request Body:
{
"userPublicKey": "Base58...",
"quoteResponse": { },
"dynamicComputeUnitLimit": true,
"prioritizationFeeLamports": 150000,
"wrapAndUnwrapSol": true
}
Response:
{
"swapTransaction": "base64...",
"computeUnitLimit": 200000,
"lastValidBlockHeight": 123456789,
"prioritizationFeeLamports": 150000
}
POST /swap-instructions
Returns individual instructions instead of a full transaction (for custom transaction building).
Declarative Swap Endpoints
Declarative swaps use intent-based execution with deferred route optimization.
GET /intent
Get an intent quote for a declarative swap.
| Parameter | Required | Description |
|---|
inputMint | Yes | Base58 input mint |
outputMint | Yes | Base58 output mint |
amount | Yes | Input amount (scaled integer) |
slippageBps | No | Slippage tolerance |
userPublicKey | Yes | User's wallet address |
POST /submit-intent
Submit a signed intent transaction for execution.
Request Body:
{
"signedTransaction": "base64...",
"intentResponse": { }
}
Token API Endpoints
GET /tokens
Returns list of supported token mints.
GET /tokens-with-decimals
Returns tokens with decimal information for proper amount scaling.
Venue API Endpoints
GET /venues
Returns list of supported DEX venues (Raydium, Orca, Phoenix, Lifinity, etc.).
Swap Modes Comparison
| Feature | Imperative | Declarative |
|---|
| Route Control | Full control at sign time | Optimized at execution |
| Latency | Higher (two API calls) | Lower (deferred calc) |
| Slippage | Fixed at quote time | Minimized at execution |
| Sandwich Protection | Standard | Enhanced |
| Use Case | Precise route requirements | Best execution priority |
When to Use Imperative
- Need to review exact route before signing
- Building order books or specific DEX routing
- Complex multi-step transactions
- Need deterministic execution paths
When to Use Declarative
- Prioritize best execution
- Lower slippage requirements
- Simple token swaps
- MEV protection is important
Execution Modes
Synchronous (Atomic)
- Single transaction execution
- All-or-nothing settlement
- Standard confirmation flow
- Use
connection.confirmTransaction()
Asynchronous (Multi-Transaction)
- Uses Jito bundles
- Open → Fill → Close transaction flow
- Poll
/order-status for completion
- Better for complex routes or prediction markets
async function monitorAsyncOrder(signature: string) {
const statuses = ["pending", "open", "pendingClose"];
let currentStatus = "pending";
while (statuses.includes(currentStatus)) {
await new Promise(r => setTimeout(r, 2000));
const res = await fetch(
`${API_BASE}/order-status?signature=${signature}`,
{ headers: { "x-api-key": API_KEY } }
).then(r => r.json());
currentStatus = res.status;
if (currentStatus === "closed") {
return { success: true, fills: res.fills };
}
if (currentStatus === "failed" || currentStatus === "expired") {
return { success: false, status: currentStatus };
}
}
}
Prediction Markets
DFlow provides infrastructure for trading prediction market outcome tokens.
Market Structure
Series (Collection)
└── Event (Occurrence)
└── Market (Outcome Trade)
Market Lifecycle
- Initialized - Market created
- Active - Trading enabled
- Inactive - Trading paused
- Closed - No more trading
- Determined - Outcome known
- Finalized - Payouts available
Trading Prediction Markets
const order = await fetch(`${API_BASE}/order?${new URLSearchParams({
inputMint: USDC,
outputMint: OUTCOME_TOKEN_MINT, // Prediction market token
amount: "10000000", // 10 USDC
slippageBps: "100",
userPublicKey: keypair.publicKey.toBase58(),
predictionMarketSlippageBps: "200", // Separate slippage for PM
})}`, { headers: { "x-api-key": API_KEY } }).then(r => r.json());
Common Token Mints
| Token | Mint Address |
|---|
| SOL (Wrapped) | So11111111111111111111111111111111111111112 |
| USDC | EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v |
| USDT | Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB |
| BONK | DezXAZ8z7PnrnRJjz3wXBoRgixCa6xjnB7YaB1pPB263 |
| JUP | JUPyiwrYJFskUPiHa7hkeR8VUtAeFoSYbKedZNsDvCN |
| WIF | EKpQGSJtjMFqKZ9KQanSqYXRcF8fBopzLHYxdM65zcjm |
Priority Fees
Configure transaction priority:
prioritizationFeeLamports: "auto"
prioritizationFeeLamports: {
priorityLevel: "high"
}
prioritizationFeeLamports: 150000
prioritizationFeeLamports: {
autoMultiplier: 2,
maxLamports: 500000
}
Error Handling
async function safeSwap(params: SwapParams) {
try {
const quote = await getQuote(params);
if (!quote.routePlan?.length) {
throw new Error("No route found");
}
const swap = await getSwapTransaction(quote, params.userPublicKey);
const tx = deserializeTransaction(swap.swapTransaction);
tx.sign([params.keypair]);
const signature = await connection.sendTransaction(tx, {
skipPreflight: false,
maxRetries: 3,
});
return { success: true, signature };
} catch (error) {
if (error.message.includes("insufficient")) {
return { success: false, error: "Insufficient balance" };
}
if (error.message.includes("slippage")) {
return { success: false, error: "Slippage exceeded" };
}
return { success: false, error: error.message };
}
}
Platform Fees
Collect platform fees on swaps:
const quote = await fetch(`${API_BASE}/quote?${new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000",
platformFeeBps: "50", // 0.5% fee
platformFeeMode: "outputMint", // Collect in output token
})}`, { headers: { "x-api-key": API_KEY } }).then(r => r.json());
const swap = await fetch(`${API_BASE}/swap`, {
method: "POST",
headers: { "content-type": "application/json", "x-api-key": API_KEY },
body: JSON.stringify({
userPublicKey: user.toBase58(),
quoteResponse: quote,
feeAccount: platformFeeAccount.toBase58(),
}),
}).then(r => r.json());
Jito Integration
For MEV protection and bundle submission:
const quote = await fetch(`${API_BASE}/quote?${new URLSearchParams({
inputMint: SOL,
outputMint: USDC,
amount: "1000000000",
forJitoBundle: "true",
})}`, { headers: { "x-api-key": API_KEY } }).then(r => r.json());
const swap = await fetch(`${API_BASE}/swap`, {
method: "POST",
body: JSON.stringify({
userPublicKey: user.toBase58(),
quoteResponse: quote,
includeJitoSandwichMitigationAccount: true,
}),
}).then(r => r.json());
DFlow Swap Orchestrator
The DFlow Swap Orchestrator contract manages declarative swap execution:
Program ID: DF1ow3DqMj3HvTj8i8J9yM2hE9hCrLLXpdbaKZu4ZPnz
Skill Structure
dflow/
├── SKILL.md # This file
├── resources/
│ ├── api-reference.md # Complete API reference
│ ├── token-mints.md # Common token addresses
│ └── error-codes.md # Error handling guide
├── examples/
│ ├── imperative-swaps/ # Imperative swap examples
│ ├── declarative-swaps/ # Declarative swap examples
│ ├── trade-api/ # Unified Trade API examples
│ └── prediction-markets/ # Prediction market examples
├── templates/
│ └── swap-client.ts # Copy-paste starter
└── docs/
├── advanced-patterns.md # Complex integrations
└── troubleshooting.md # Common issues
Guidelines
- Use Trade API for most cases - Unified endpoint handles both sync/async
- Always handle async orders - Check
executionMode and poll status
- Set appropriate slippage - "auto" for convenience, custom for control
- Include priority fees - Essential for reliable execution
- Handle errors gracefully - Network issues, slippage, insufficient balance
- Monitor rate limits - Use API key for production
- Test on devnet first - DFlow supports Solana devnet
Resources