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.
Use the Metadata API to discover markets and map outcome token mints for trading.

Get Events with Nested Markets

You get events (real-world questions) and include their nested markets so you can read outcome mints from the accounts field. If you need the data model, review Event fields.
const METADATA_API_BASE_URL = "https://dev-prediction-markets-api.dflow.net";

const response = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/events?withNestedMarkets=true&limit=200`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!response.ok) {
  throw new Error("Failed to get events");
}

const data = await response.json();
const events = data.events;

events.forEach((event: any) => {
  console.log("Event:", {
    ticker: event.ticker,
    title: event.title,
    subtitle: event.subtitle,
    seriesTicker: event.seriesTicker,
  });

  if (event.markets && event.markets.length > 0) {
    event.markets.forEach((market: any) => {
      const accountValues = Object.values(market.accounts);

      console.log("  Market:", {
        ticker: market.ticker,
        title: market.title,
        status: market.status,
        accounts: accountValues.map((account: any) => ({
          yesMint: account.yesMint,
          noMint: account.noMint,
        })),
      });
    });
  }
});

Filter Events by Market Status

Filter events to focus on markets that match a given status (for example, active vs. initialized). If you need the full status flow, see Prediction Market Lifecycle.
const METADATA_API_BASE_URL = "https://dev-prediction-markets-api.dflow.net";

const response = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/events?withNestedMarkets=true&status=active&limit=200`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!response.ok) {
  throw new Error("Failed to get events");
}

const data = await response.json();
const events = data.events;

events.forEach((event: any) => {
  if (event.markets && event.markets.length > 0) {
    event.markets.forEach((market: any) => {
      const accountValues = Object.values(market.accounts);

      console.log("Market:", {
        ticker: market.ticker,
        title: market.title,
        status: market.status,
        accounts: accountValues.map((account: any) => ({
          yesMint: account.yesMint,
          noMint: account.noMint,
        })),
      });
    });
  }
});
const METADATA_API_BASE_URL = "https://dev-prediction-markets-api.dflow.net";

const response = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/events?withNestedMarkets=true&status=initialized&limit=200`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!response.ok) {
  throw new Error("Failed to get events");
}

const data = await response.json();
const events = data.events;

events.forEach((event: any) => {
  if (event.markets && event.markets.length > 0) {
    event.markets.forEach((market: any) => {
      const accountValues = Object.values(market.accounts);

      console.log("Market:", {
        ticker: market.ticker,
        title: market.title,
        status: market.status,
        accounts: accountValues.map((account: any) => ({
          yesMint: account.yesMint,
          noMint: account.noMint,
        })),
      });
    });
  }
});

Get All Markets for a Specific Asset

If you know the asset you want (e.g., Bitcoin, SOL), the fastest approach is to query the events endpoint directly with the seriesTickers parameter. Each asset has a root series ticker (e.g., KXBTC for Bitcoin, KXSOL for SOL) that covers all market types for that asset.
const METADATA_API_BASE_URL = "https://dev-prediction-markets-api.dflow.net";

// Use the root series ticker for the asset (e.g., KXBTC for Bitcoin)
const response = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/events?withNestedMarkets=true&seriesTickers=KXBTC&status=active`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!response.ok) {
  throw new Error("Failed to get events");
}

const data = await response.json();
const events = data.events;

events.forEach((event: any) => {
  console.log("Event:", {
    ticker: event.ticker,
    title: event.title,
  });

  if (event.markets && event.markets.length > 0) {
    event.markets.forEach((market: any) => {
      const accountValues = Object.values(market.accounts);

      console.log("  Market:", {
        ticker: market.ticker,
        title: market.title,
        status: market.status,
        accounts: accountValues.map((account: any) => ({
          yesMint: account.yesMint,
          noMint: account.noMint,
        })),
      });
    });
  }
});
If you don’t know the series ticker for an asset, use the series endpoint with a category and tag to find it first. For example, /api/v1/series?category=Crypto&tags=SOL returns all series tickers that start with KXSOL. You can then pass those tickers to the events endpoint. For broader discovery without a specific asset in mind, use the categories and tags approach below.

Filter Events by Categories and Tags

Use tags to find relevant series (event templates) and then get events for those series. This keeps discovery focused without hardcoding tickers.
const METADATA_API_BASE_URL = "https://dev-prediction-markets-api.dflow.net";

const response = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/tags_by_categories`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!response.ok) {
  throw new Error("Failed to get tags by categories");
}

const data = (await response.json()) as { tagsByCategories: Record<string, any[]> };
const tagsByCategories = data.tagsByCategories;

Object.entries(tagsByCategories).forEach(
    ([category, tags]: [string, any]) => {
        const tagList = Array.isArray(tags) ? tags.join(", ") : String(tags ?? "");
        console.log(`Tags for ${category}: ${tagList}`);
    }
);
const METADATA_API_BASE_URL = "https://dev-prediction-markets-api.dflow.net";

const selectedCategory = "Sports";
const selectedTag = "Football";

const responseByCategory = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/series?category=${selectedCategory}`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

const dataByCategory = await responseByCategory.json();
const categorizedSeriesTickers = dataByCategory.series.map((s: any) => s.ticker);

const responseByTag = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/series?tags=${selectedTag}`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!responseByTag.ok) {
  throw new Error("Failed to get series");
}

const dataByTag = await responseByTag.json();
const taggedSeriesTickers = dataByTag.series.map((s: any) => s.ticker);

const selectedTags = "Football,Soccer";
const responseWithBoth = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/series?category=${selectedCategory}&tags=${selectedTags}`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

const dataWithBoth = await responseWithBoth.json();
const filteredSeries = dataWithBoth.series;
const seriesTickers = filteredSeries.map((s: any) => s.ticker);
const METADATA_API_BASE_URL = "https://dev-prediction-markets-api.dflow.net";

const selectedSeriesTicker = seriesTickers[0];

const response = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/events?seriesTickers=${selectedSeriesTicker}&withNestedMarkets=true&limit=100`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

const multipleSeriesTickers = seriesTickers.slice(0, 3).join(",");
const responseMultiple = await fetch(
  `${METADATA_API_BASE_URL}/api/v1/events?seriesTickers=${multipleSeriesTickers}&withNestedMarkets=true&limit=100`,
  {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
  }
);

if (!response.ok) {
  throw new Error("Failed to get events by series");
}

const data = await response.json();
const filteredEvents = data.events;

filteredEvents.forEach((event: any) => {
  console.log("Event:", {
    ticker: event.ticker,
    title: event.title,
    subtitle: event.subtitle,
    seriesTicker: event.seriesTicker,
  });

  if (event.markets && event.markets.length > 0) {
    event.markets.forEach((market: any) => {
      const accountValues = Object.values(market.accounts);

      console.log("  Market:", {
        ticker: market.ticker,
        title: market.title,
        status: market.status,
        accounts: accountValues.map((account: any) => ({
          yesMint: account.yesMint,
          noMint: account.noMint,
        })),
      });
    });
  }
});

Review API Responses

Use event and series responses to extract outcome mints and filter markets. If you only need outcome mints, you can skip to the accounts map in each market object.

Events Response

You receive event metadata and nested markets (when withNestedMarkets=true), including yesMint and noMint in market accounts.

Tags by Categories Response

You receive a map of categories to tag arrays, which you use to filter series.

Series Response

You receive series metadata, including ticker, title, category, tags, and frequency.

KYC Requirements

Prediction market applications must use Proof to meet Kalshi compliance requirements.

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.