Skip to main content
During development, you can use the developer endpoints without an API key. For production use, you’ll need an API key to avoid rate limits.
When working with prediction markets, you use the Metadata API to discover markets, and the Trade API to trade them. This receipe demonstrates how to trade a prediction market outcome token.
This recipe assumes familiarity with Solana’s transaction and network connection logic. If unfamiliar, please refer to the Solana Cookbook.
1

Request an Order

The Trade API’s GET /order endpoint returns a quote and open transaction in a single request.
const SOL = "So11111111111111111111111111111111111111112";
const USDC = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

/// Amount of SOL to trade to USDC
const amount = 1_000_000_000;

/// Slippage tolerance in bps
const slippageBps = 50;

/// Base URL for the DFlow Trade API
const API_BASE_URL = "https://dev-quote-api.dflow.net";
const API_KEY = process.env.DFLOW_API_KEY; // Optional

const queryParams = new URLSearchParams();
queryParams.append("inputMint", SOL);
queryParams.append("outputMint", USDC);
queryParams.append("amount", amount.toString());
queryParams.append("slippageBps", slippageBps.toString());
queryParams.append("userPublicKey", keypair.publicKey.toBase58());

const headers: HeadersInit = {};
if (API_KEY) {
  headers["x-api-key"] = API_KEY;
}

const orderResponse = await fetch(
  `${API_BASE_URL}/order?${queryParams.toString()}`,
  { headers }
).then((x) => x.json());
2

Sign and Submit the Transaction

Deserialize the transaction, sign it with your keypair, and submit it to Solana using your RPC connection.
/// Deserialize the transaction from base64
const transactionBuffer = Buffer.from(orderResponse.transaction, "base64");
const transaction = VersionedTransaction.deserialize(transactionBuffer);

/// Sign the transaction
transaction.sign([keypair]);

/// Send the transaction to Solana
const signature = await connection.sendTransaction(transaction);
3

Monitor Order Status

How you monitor order completion depends on the executionMode returned from the order request:Sync trades execute atomically in a single transaction. Use standard RPC confirmation.Async trades execute across multiple transactions. Use the /order-status endpoint to poll for completion.
For synchronous trades that execute atomically, use standard Solana transaction confirmation:
if (orderData.executionMode === "sync") {
  /// Monitor transaction status using getSignatureStatuses
  let status;

  do {
    const statusResult = await connection.getSignatureStatuses([signature]);
    status = statusResult.value[0];

    if (!status) {
      console.log("Waiting for transaction confirmation...");
      await new Promise((resolve) => setTimeout(resolve, 1000));
    }
  } while (
    !status ||
    status.confirmationStatus === "processed" ||
    status.confirmationStatus === "confirmed"
  );

  /// Check if transaction succeeded or failed
  if (status.err) {
    console.error("Transaction failed:", status.err);
  } else {
    console.log(`Trade completed successfully in slot ${status.slot}`);
  }
}
For asynchronous trades that execute across multiple transactions, poll the /order-status endpoint:
if (orderData.executionMode === "async") {
  let status;
  let fills = [];

  do {
    /// Poll the order status endpoint
    const headers: HeadersInit = {};
    if (API_KEY) {
      headers["x-api-key"] = API_KEY;
    }
    const statusResponse = await fetch(
      `${API_BASE_URL}/order-status?signature=${signature}`,
      { headers }
    );
    const statusData = await statusResponse.json();

    status = statusData.status;
    fills = statusData.fills || [];

    console.log(`Order status: ${status}`);

    /// Wait before polling again if order is still open
    if (status === "open" || status === "pendingClose") {
      await new Promise((resolve) => setTimeout(resolve, 2000));
    }
  } while (status === "open" || status === "pendingClose");

  /// Process final status
  switch (status) {
    case "closed": {
      if (fills.length > 0) {
        console.log(`Trade completed`);
      } else {
        console.log("Order was closed without any fills");
      }
      break;
    }
    case "pendingClose": {
      if (fills.length > 0) {
        console.log(`Trade ready to close`);
      } else {
        console.log("Order is ready to close without any fills");
      }
      break;
    }
    case "failed": {
      console.log("Order failed to execute");
      break;
    }
  }
}

API Routes

Cookbook Repository

This recipe, along with many more, is available in the DFlow Cookbook Repo. You can clone it and start coding immediately.