Skip to main content
This guide shows you how to redeem determined prediction market outcome tokens by checking if they’re redeemable and requesting a redemption order through the DFlow Trade API.
This quickstart assumes you already have a list of outcome token mints you want to redeem. If you need to discover your positions first, see the User Prediction Positions guide.Redemption involves trading expired OutcomeTokens for the stablecoin you opened your position with. For more details on the settlement process, see the Event Settlement and Redemption concept guide.Note: Outcome tokens always have 0 decimals, so the amount to redeem is the raw token count from the user’s token balance.

Overview

To redeem determined market outcome tokens, you’ll need to:
  1. Check if the outcome token is redeemable by verifying market status and redemption availability
  2. Request a redemption order using the DFlow Trade API
  3. Sign and submit the transaction (same process as regular trading)
1

Check if Outcome Token is Redeemable

Use the /api/v1/market/by-mint/{mint_address} endpoint to fetch market details and verify that the outcome token is redeemable. A token is redeemable when:
  • The market status is "determined" or "finalized"
  • The market result ("yes" or "no") matches the user’s outcome token (the outcome mint must match the yesMint or noMint for the determined side)
  • The redemption status for the settlement mint is "Open"
/// Base URL for the DFlow Prediction Market Metadata API
const METADATA_API_BASE_URL = "https://prediction-markets-api.dflow.net";

/// Settlement mint constant (USDC)
/// If you only support one settlement mint, use this constant
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

/// Outcome token mint address (YES or NO token)
const outcomeMint = "OUTCOME_TOKEN_MINT_ADDRESS_HERE";

/// Fetch market details by mint address
const response = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/market/by-mint/${outcomeMint}`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!response.ok) {
  throw new Error("Failed to fetch market details");
}

const market = await response.json();

/// Check if market is determined (status can be "determined" or "finalized")
if (market.status !== "determined" && market.status !== "finalized") {
  throw new Error(`Market is not determined. Current status: ${market.status}`);
}

/// Check if the outcome mint matches the market result
/// The result is "yes" or "no", so we need to check if the outcome mint
/// matches the corresponding yesMint or noMint in the accounts
const result = market.result; // "yes" or "no"
let isDeterminedOutcome = false;
let settlementMint;

/// Option 1: Use a constant settlement mint (e.g., USDC)
/// If you only support one settlement mint, use this approach
if (market.accounts[USDC_MINT]) {
  const usdcAccount = market.accounts[USDC_MINT];

  /// Check if redemption is open and outcome matches
  if (usdcAccount.redemptionStatus === "open") {
    if (
      (result === "yes" && usdcAccount.yesMint === outcomeMint) ||
      (result === "no" && usdcAccount.noMint === outcomeMint)
    ) {
      isDeterminedOutcome = true;
      settlementMint = USDC_MINT;
    }
  } else {
    throw new Error(`Redemption is not open for ${outcomeMint}`);
  }
}

/// Option 2: Find settlement mint dynamically (if you support multiple)
/// Uncomment this if you need to support multiple settlement mints
/*
if (!settlementMint) {
  for (const [mint, account] of Object.entries(market.accounts)) {
    if (account.redemptionStatus === "open") {
      /// Check if this outcome mint matches the determined side
      if (result === "yes" && account.yesMint === outcomeMint) {
        isDeterminedOutcome = true;
        settlementMint = mint;
        break;
      } else if (result === "no" && account.noMint === outcomeMint) {
        isDeterminedOutcome = true;
        settlementMint = mint;
        break;
      }
    } else {
      throw new Error(`Redemption is not open for ${outcomeMint}`);
    }
  }
}
*/

if (!isDeterminedOutcome) {
  throw new Error(
    `Outcome token does not match market result. Market result: ${result}, Token: ${outcomeMint}`
  );
}

if (!settlementMint) {
  throw new Error("No settlement mint with open redemption status found");
}

const settlementAccount = market.accounts[settlementMint];

console.log("Token is redeemable!", {
  outcomeMint,
  settlementMint,
  redemptionStatus: settlementAccount.redemptionStatus,
  marketTitle: market.title,
});
2

Request Redemption Order

Use the Trade API /order endpoint to request a redemption order. The redemption is treated as a trade where you swap your outcome token for the settlement stablecoin.
/// Base URL for the DFlow Trade API
const API_BASE_URL = "https://quote-api.dflow.net";

/// Settlement mint constant (USDC)
const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";

/// Outcome token mint (YES or NO token you hold)
const outcomeMint = "OUTCOME_TOKEN_MINT_ADDRESS_HERE";

/// Settlement mint (use the constant or the value found in Step 1)
const settlementMint = USDC_MINT;

/// Amount of outcome tokens to redeem
/// Outcome tokens always have 0 decimals, so the amount is the raw token count
/// Get this from the user's token balance (rawBalance from token account)
const amount = 1; // Example: 1 outcome token (0 decimals)

/// User's public key
const userPublicKey = keypair.publicKey.toBase58();

const queryParams = new URLSearchParams();
queryParams.append("userPublicKey", userPublicKey);
queryParams.append("inputMint", outcomeMint);
queryParams.append("outputMint", settlementMint);
queryParams.append("amount", amount.toString());

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

console.log(
  `Redemption order received! ${orderResponse.inAmount} of ${orderResponse.inputMint} is redeemable for ${orderResponse.outAmount} of ${orderResponse.outputMint}`
);
3

Sign and Submit Redemption Transaction

The redemption transaction follows the same workflow as regular trading. Deserialize the transaction, sign it with your keypair, and submit it to Solana. Then monitor the order status based on the execution mode.
Redemption uses the same Trade API workflow as regular trading. Follow the steps in the Trade Tokens quickstart to:
  1. Sign the Transaction: Deserialize the transaction from base64 and sign it with your keypair
  2. Submit to Solana: Send the signed transaction to your Solana RPC connection
  3. Monitor Order Status:
    • For sync trades: Use standard RPC confirmation
    • For async trades: Poll the /order-status endpoint
The transaction returned from the redemption order request should be handled exactly like a regular trade transaction. See the Trade Tokens guide for complete code examples.

API Response Structure

Market Response

The /api/v1/market/by-mint/{mint_address} endpoint returns market data including:
  • Status: Market status ("determined" or "finalized" when outcome is finalized)
  • Result: The determined outcome as a string ("yes" or "no")
  • Accounts: Object mapping settlement mint addresses (e.g., "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" for USDC) to account information:
    • yesMint: YES outcome token mint address
    • noMint: NO outcome token mint address
    • redemptionStatus: Redemption status ("Open" when redemption is available, "pending" when not yet available)
    • marketLedger: Market ledger account address

Order Response

The Trade API /order endpoint returns:
  • Transaction: Base64-encoded transaction ready to sign and submit
  • Execution Mode: "sync" (atomic) or "async" (multi-transaction)
  • Quote information including expected output amount

Next Steps