Skip to content

Quickstart

Pull your first matched feed over REST on a free key, then connect the real-time stream.

This walks you from nothing to live data in about two minutes. The first half runs on a free key. The second half connects the real-time stream and needs a Basic or Pro plan.

First, create an API key. Open the dashboard, sign in with GitHub or Google, and create a key. It is shown once, so copy it somewhere safe. Every new key starts on Free, which is all you need for the first half.

The matched feed over REST

The REST snapshot gives you the matched feed, priced with the arb view when you ask for it. Ask for one sport to keep the response small. Send your key as a bearer token.

curl -s "https://api.dino.markets/v2/markets?signal=arb&sport=baseball" \
  -H "Authorization: Bearer sk_live_..."

You get back the snapshot for that sport. Here is one confirmed arb:

{
  "count": 1,
  "sport": "baseball",
  "has_more": false,
  "markets": [
    {
      "id": "dino_8f3a1c92-47e8-4c3f-b9d2-f1a8e6c4d5f2",
      "slug": null,
      "sport": "baseball",
      "league": "MLB",
      "title": "Nyy vs Bos",
      "home": null,
      "away": null,
      "start_time": "2026-07-01T23:05:00+00:00",
      "status": "open",
      "match": "high_confidence",
      "signal": "arb",
      "spread_pts": 2.0,
      "potential_arb_pct": 1.83,
      "coverage": { "kalshi": true, "polymarket": true },
      "outcomes": [
        { "key": "NYY", "name": "NYY", "kalshi": 0.52, "polymarket": 0.54, "cheaper": "kalshi" },
        { "key": "BOS", "name": "BOS", "kalshi": 0.50, "polymarket": 0.46, "cheaper": "polymarket" }
      ],
      "result": null,
      "updated_at": "2026-07-01T22:55:00+00:00",
      "priced_at": "2026-07-01T22:55:00+00:00",
      "links": { "kalshi": "https://kalshi.com/markets/KXMLBGAME-26JUL01NYYBOS", "polymarket": null }
    }
  ]
}

GET /v2/markets?signal=arb returns the canonical market object, priced. potential_arb_pct is the gross ask-to-ask return, before venue fees. outcomes lists each market outcome with its price on both venues and which venue has the lower ask (cheaper). signal is "arb" when the matcher has confirmed cross-venue settlement parity on the decided outcome; anything else, including a matched gap with settlement risk disclosed, comes back as "spread". Either way, read settlement.risks before acting. Add include=settlement or call the detail endpoint below.

For the full detail (venue handles, confidence, settlement disclosure), call GET /v2/pairs/{market_id} using the id from the row. That detail only changes when the matcher re-analyses the live text, so cache it.

When nothing is open, markets is an empty array and count is 0. That is the normal resting state between arbs, not an error. You can narrow the snapshot further with sport and limit.

The real-time stream

The REST snapshot is about two minutes behind, so it is for exploring. To act on an arb the moment it opens, read the WebSocket stream. This needs a Basic or Pro key.

The stream is a two-step handshake. You mint a short-lived ticket over REST, then open the socket with it. A Free key gets a 402 here with a link to upgrade.

Step one, mint a ticket. It is valid for about 120 seconds:

curl -s -X POST "https://api.dino.markets/v1/stream/token" \
  -H "Authorization: Bearer sk_live_..."
{
  "ticket": "eyJhbGciOi...",
  "ws_url": "wss://stream.dino.markets/connection/websocket",
  "expires_in": 120,
  "allowed": {
    "channels": ["markets:all", "status"],
    "max_conns": 3
  }
}

Step two, connect. The stream speaks the Centrifugo protocol, so use the centrifuge client for your language and pass the ticket in the connect data under t. You do not subscribe by hand. The server reads your plan from the ticket and pushes the channels you are entitled to.

import { Centrifuge } from "centrifuge";

const centrifuge = new Centrifuge("wss://stream.dino.markets/connection/websocket", {
  data: { t: ticket },
});

centrifuge.on("publication", (ctx) => {
  console.log(ctx.channel, ctx.data);
});

centrifuge.connect();

Messages are pushed the instant something changes: market state and price delta frames on the markets:* channels; when a pair's signal is arb, its frames also carry the per-outcome depth books and max_stake. The WebSocket stream page covers each shape.

Next

The Market object reference covers the canonical object shape, the outcomes array, signal types, and the stream envelope. The WebSocket stream page covers connecting and how to recover after a disconnect. For venue handles and settlement terms, use GET /v2/pairs/{market_id} documented in the REST reference.