# Diamond API Documentation

> **SkyProvider.cc Aggregator API v2**  
> **Base URL:** `http://145.79.12.201:3001/api/v2/diamond/`  
> **Last Updated:** 2026-05-16

---

## Table of Contents

1. [Overview](#1-overview)
2. [Authentication](#2-authentication)
3. [Endpoints Reference](#3-endpoints-reference)
4. [Data Models](#4-data-models)
5. [Full Markets Scraping](#5-full-markets-scraping)
6. [Casino System](#6-casino-system-in-depth)
7. [Odds & Calculations](#7-odds--calculations)
8. [Domain Rotation System](#8-domain-rotation-system)
9. [Implementation Guide](#9-implementation-guide-for-aggregators)
10. [External APIs for Expansion](#10-external-apis-for-expansion)
11. [Code Examples](#11-code-examples)
12. [Troubleshooting](#12-troubleshooting)

---

## 1. Overview

The **Diamond API** is a unified REST API that aggregates live sports betting data from multiple upstream exchange sources into a single, normalized interface.

### Architecture

```
┌─────────────────────────────────────────────────────────────┐
│                    Diamond API v2                           │
│  ┌─────────────┐  ┌──────────────┐  ┌──────────────────┐   │
│  │  /sports    │  │  /games      │  │  /highlights     │   │
│  │  /open-bets │  │  /betslips   │  │  /tokens         │   │
│  │  /tables    │  │  /userinfo   │  │  /status         │   │
│  └──────┬──────┘  └──────┬───────┘  └────────┬─────────┘   │
│         └─────────────────┴───────────────────┘             │
│                           │                                 │
│              ┌────────────┴────────────┐                    │
│              │   diamondController.js  │                    │
│              └────────────┬────────────┘                    │
│                           │                                 │
│         ┌─────────────────┼─────────────────┐               │
│         │                 │                 │               │
│    ┌────┴────┐      ┌────┴────┐      ┌────┴────┐          │
│    │imatchodds│      │mouseexch│      │allpanel │          │
│    │  LIVE   │      │ DISABLED│      │ DISABLED│          │
│    └────┬────┘      └─────────┘      └─────────┘          │
│         │                                                   │
│    ┌────┴────┐                                             │
│    │ Playwright│ ← Stealth browser, demo login            │
│    │  poller   │   reads Vue 3 localStorage every 20s     │
│    └───────────┘                                             │
└─────────────────────────────────────────────────────────────┘
```

### Active Upstreams

| Source | Status | Games | Sports | Type |
|--------|--------|-------|--------|------|
| **imatchodds** (silver247x.com) | ✅ Live | 30-60 | 4 | Vue 3 localStorage scrape |
| mouseexch | ❌ Disabled | 0 | 0 | EcoAssets v103 — all domains dead |
| allpanel | ❌ Disabled | 0 | 0 | EcoAssets v103 — all domains dead |

### Data Flow

1. **Poller** (`imatchoddsPoller.js`) launches a stealth Playwright browser every 20 seconds
2. Navigates to `silver247x.com`, clicks **Demo** login
3. Reads `TreeSportWithEvent`, `games`, `OpenBets`, `betslips`, `userinfo`, tokens from Vue app's `localStorage`
4. Normalizes data (parses `summaryMarkets` JSON, extracts runners with back/lay)
5. Caches to in-memory store with 60s TTL
6. **Controller** (`diamondController.js`) serves cached data via REST endpoints

---

## 2. Authentication

All Diamond API endpoints require password authentication.

### Methods

**Query Parameter:**
```
GET /api/v2/diamond/sports?password=Lav@9868@
```

**Header (preferred):**
```
x-password: Lav@9868@
```

### Response (unauthorized)
```json
{
  "success": false,
  "error": "Unauthorized"
}
```

---

## 3. Endpoints Reference

### 3.1 GET /sports

List all active sports with event counts.

**Request:**
```bash
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/sports"
```

**Response:**
```json
{
  "success": true,
  "data": {
    "count": 4,
    "sports": [
      {
        "id": "3",
        "name": "Cricket",
        "eventCount": 10,
        "_source": "imatchodds"
      },
      {
        "id": "2",
        "name": "Tennis",
        "eventCount": 4,
        "_source": "imatchodds"
      },
      {
        "id": "1",
        "name": "Football",
        "eventCount": 22,
        "_source": "imatchodds"
      },
      {
        "id": "26",
        "name": "Horse Racing",
        "eventCount": 2,
        "_source": "imatchodds"
      }
    ]
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.2 GET /games

List all games with live odds, or filter by sport.

**Query Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `sport_id` | string | Filter by sport ID (e.g., `3` for Cricket) |
| `etid` | string | Alias for `sport_id` |

**Request:**
```bash
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/games?sport_id=3"
```

**Response:**
```json
{
  "success": true,
  "data": {
    "count": 10,
    "games": [
      {
        "gmid": "5359254",
        "etid": 3,
        "sportName": "Cricket",
        "title": "England W v New Zealand W",
        "league": "Metro Bank Womens One Day Cup",
        "team1": "England W",
        "team2": "New Zealand W",
        "status": "IN_PLAY",
        "startTime": "2026-05-16T15:00:00",
        "matchDate": "In-Play",
        "isLive": true,
        "isFancy": true,
        "isBookMaker": true,
        "videoURL": "<iframe ... src='https://getscoredata.com/score/...'></iframe>",
        "marketName": "Match Odds",
        "runners": [
          {
            "name": "England W",
            "back": [{ "price": 90.0, "size": 1740 }],
            "lay": [{ "price": 95.0, "size": 10000 }],
            "status": "Normal",
            "marketName": "Match Odds"
          },
          {
            "name": "New Zealand W",
            "back": [{ "price": 1.01, "size": 57614540 }],
            "lay": [{ "price": 1.02, "size": 39663960 }],
            "status": "Normal",
            "marketName": "Match Odds"
          }
        ],
        "_rawMarkets": [...],
        "_source": "imatchodds"
      }
    ]
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.3 GET /highlights

Get in-play and upcoming games grouped by status.

**Query Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `sport_id` | string | Filter by sport ID. If omitted, returns ALL sports. |
| `etid` | string | Alias for `sport_id` |

**Request:**
```bash
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/highlights?sport_id=3"
```

**Response:**
```json
{
  "success": true,
  "data": {
    "t1": [],
    "inplay": [
      {
        "gmid": "5359254",
        "title": "England W v New Zealand W",
        "isLive": true,
        "runners": [...],
        "_source": "imatchodds"
      }
    ],
    "upcoming": [
      {
        "gmid": "5315403",
        "title": "Test a vs test b",
        "isLive": false,
        "runners": [],
        "_source": "imatchodds"
      }
    ],
    "_sources": {
      "imatchodds": true
    }
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.4 GET /games/:gmid

Get game snapshot (same structure as `/games/:gmid/data`).

**Path Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `gmid` | string | Game/Match ID |

**Query Parameters:**
| Param | Type | Description |
|-------|------|-------------|
| `sport_id` | string | Optional sport filter for faster lookup |

---

### 3.5 GET /games/:gmid/data

Get full game data with market runners.

**Response:**
```json
{
  "success": true,
  "data": {
    "game": { /* full game object */ },
    "_source": "imatchodds"
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.6 GET /games/:gmid/detail

Get game detail (same as data endpoint, for backward compatibility).

**Query Parameters:**
| Parameter | Type | Description |
|-----------|------|-------------|
| `full` | string | Set to `1` to scrape ALL markets (Match Odds, BookMaker, Fancy) on-demand |

**Response (with `?full=1`):**
```json
{
  "success": true,
  "data": {
    "game": { /* ... game object ... */ },
    "fullMarkets": [
      {
        "name": "MatchOdds",
        "minStake": 100,
        "maxStake": 50000,
        "runners": [
          {
            "name": "Bangladesh",
            "back": [{ "price": "6.40", "size": "42k" }],
            "lay": [{ "price": "6.20", "size": "30k" }],
            "status": "ACTIVE"
          }
        ]
      },
      {
        "name": "BookMaker",
        "minStake": 100,
        "maxStake": 500000,
        "runners": [ /* ... */ ]
      },
      {
        "name": "Fancy",
        "minStake": 100,
        "maxStake": 200000,
        "runners": [ /* ... */ ]
      }
    ],
    "_source": "imatchodds",
    "_marketSource": "scraped"
  }
}
```

---

### 3.7 GET /games/:gmid/markets

**On-demand full market scrape** — navigates to the match detail page and extracts ALL markets (Match Odds, BookMaker, Fancy) from the rendered DOM.

> ⚠️ This endpoint is **slower** (~6-10s) than cached endpoints because it launches a page navigation. Results are cached for 15 seconds.

**Response:**
```json
{
  "success": true,
  "data": {
    "gmid": "5358824",
    "title": "Bangladesh v Pakistan",
    "teams": { "team1": "Bangladesh", "team2": "Pakistan" },
    "status": "IN_PLAY",
    "isFancy": true,
    "isBookMaker": true,
    "markets": [
      {
        "name": "MatchOdds",
        "minStake": 100,
        "maxStake": 50000,
        "runners": [
          {
            "name": "Bangladesh",
            "back": [{ "price": "6.40", "size": "42k" }],
            "lay": [{ "price": "6.20", "size": "30k" }],
            "status": "ACTIVE"
          }
        ]
      }
    ],
    "_source": "imatchodds",
    "_marketSource": "scraped"
  }
}
```

---

### 3.8 GET /games/:gmid/scorecard

Get live scorecard iframe URL.

**Response:**
```json
{
  "success": true,
  "data": {
    "event_id": "5359254",
    "score_iframe": "<iframe style='height: 230px; width: 100%;' src='https://getscoredata.com/score/...'></iframe>",
    "title": "England W v New Zealand W",
    "teams": {
      "team1": "England W",
      "team2": "New Zealand W"
    },
    "status": "IN_PLAY",
    "_source": "imatchodds"
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.8 GET /games/:gmid/live-tv

Get live TV/stream availability.

**Response:**
```json
{
  "success": true,
  "data": {
    "event_id": "5359254",
    "source": "imatchodds",
    "tv_available": true,
    "stream_url": "<iframe ...>",
    "note": "Direct stream URL from upstream"
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.9 GET /tables

Get casino game categories.

**Response:**
```json
{
  "success": true,
  "data": {
    "count": {
      "tables": 0,
      "casino": 12
    },
    "tables": [],
    "casino": [
      {
        "category": "Lobby",
        "categoryIcon": "https://cdn.tesla108.com/images/casino/category/Lobby.png",
        "games": [
          {
            "name": "Aviator",
            "provider": "intl",
            "gameCode": "spribe_aviator",
            "gameId": 201206,
            "imageURL": "https://cd.tesla108.com/images/casino/intl/game/sbe_aviator.png",
            "_source": "imatchodds"
          }
        ]
      }
    ],
    "_sources": {
      "imatchodds": true
    }
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.10 GET /status

Get health status from all sources.

**Response:**
```json
{
  "success": true,
  "data": {
    "sources": [
      {
        "source": "mouseexch",
        "sportsPolled": 1,
        "gamesCount": 0,
        "perSport": [{ "sportId": "4", "gameCount": 0, "highlightsAvailable": false }]
      },
      {
        "source": "allpanel",
        "sportsPolled": 1,
        "gamesCount": 0,
        "perSport": [{ "sportId": "4", "gameCount": 0, "highlightsAvailable": false }]
      },
      {
        "source": "imatchodds",
        "sportsPolled": 4,
        "gamesCount": 38,
        "perSport": [
          { "etid": 3, "name": "Cricket", "eventCount": 10 },
          { "etid": 2, "name": "Tennis", "eventCount": 4 },
          { "etid": 1, "name": "Football", "eventCount": 22 },
          { "etid": 26, "name": "Horse Racing", "eventCount": 2 }
        ]
      }
    ],
    "totalGames": 38,
    "totalSports": 6,
    "defaultEtid": "4"
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.11 GET /open-bets

Get user's open bets from demo account.

**Response:**
```json
{
  "success": true,
  "data": {
    "openBets": {
      "balance": 0,
      "exposure": 8217,
      "openBets": [
        {
          "betId": "30710139",
          "betTitle": "Indian Premier League",
          "sportId": 3,
          "eventId": 4659043,
          "marketId": 21299330,
          "marketName": "Winner",
          "betType": "Lay",
          "betRate": 7,
          "stake": 3417,
          "expectedProfit": 3417,
          "expectedLoss": 20502,
          "placeTime": "2026-03-30 14:16:40",
          "eventStartTime": "2026-05-19 19:30:00"
        }
      ]
    }
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.12 GET /betslips

Get betslip stake configurations.

**Response:**
```json
{
  "success": true,
  "data": {
    "betslips": [
      {
        "title": "10",
        "value": 200,
        "index": 0,
        "creationTime": "2026-05-15T09:10:55.2421071",
        "id": 420398
      },
      {
        "title": "600",
        "value": 600,
        "index": 0,
        "creationTime": "2026-05-15T09:10:55.2421104",
        "id": 420399
      }
    ]
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.13 GET /userinfo

Get demo user info and preferences.

**Response:**
```json
{
  "success": true,
  "data": {
    "userinfo": {
      "football": true,
      "tennis": true,
      "cricket": true,
      "election": true,
      "horseRacing": false,
      "kabaddi": false,
      "trade": true,
      "aura": true,
      "international": true,
      "mac": true,
      "king": true,
      "casinoToken": "eyJhbGci...",
      "balance": 0,
      "exposure": 8217,
      "stakes": [
        { "title": "10", "value": 200, "id": 420398 },
        { "title": "600", "value": 600, "id": 420399 }
      ]
    }
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

### 3.14 GET /tokens

Get auth tokens and base URLs.

**Response:**
```json
{
  "success": true,
  "data": {
    "casinoToken": "eyJhbGci...",
    "accessToken": "eyJhbGci...",
    "baseUrl": "https://api.imatchodds.com",
    "domainSetting": { /* domain config */ }
  },
  "timestamp": "2026-05-16T18:00:00.000Z"
}
```

---

## 4. Data Models

### Sport
```typescript
interface Sport {
  id: string;          // Sport ID (e.g., "3" for Cricket)
  name: string;        // Display name
  eventCount: number;  // Number of events
  _source: string;     // Upstream source name
}
```

### Game
```typescript
interface Game {
  gmid: string;           // Game/Match ID
  etid: number;           // Sport ID
  sportName: string;      // Sport name
  title: string;          // Match title
  league: string;         // League/Tournament name
  team1: string;          // Team A name
  team2: string;          // Team B name
  status: string;         // "IN_PLAY" | "OPEN" | etc.
  startTime: string;      // ISO 8601 start time
  matchDate: string;      // Display date
  isLive: boolean;        // Currently in play
  isFancy: boolean;       // Fancy markets available
  isBookMaker: boolean;   // Bookmaker available
  videoURL: string;       // Score iframe HTML
  marketName: string;     // Primary market name
  runners: Runner[];      // Market runners with odds
  _rawMarkets: any[];     // Raw upstream market data
  _source: string;        // "imatchodds"
}
```

### Runner
```typescript
interface Runner {
  name: string;           // Runner/team name
  back: PriceLevel[];     // Back (buy) odds
  lay: PriceLevel[];      // Lay (sell) odds
  status: string;         // "Normal" | "Closed" | etc.
  marketName: string;     // Parent market name
}

interface PriceLevel {
  price: number;          // Odds price (e.g., 1.85)
  size: number;           // Available liquidity
}
```

### OpenBet
```typescript
interface OpenBet {
  betId: string;
  betTitle: string;
  sportId: number;
  eventId: number;
  marketId: number;
  marketName: string;
  betType: "Back" | "Lay";
  betRate: number;        // Odds at placement
  stake: number;
  expectedProfit: number;
  expectedLoss: number;
  placeTime: string;
  eventStartTime: string;
}
```

---

## 5. Full Markets Scraping

### Problem

The Vue 3 app on silver247x.com stores only **summaryMarkets** (1 market per event — typically Match Odds) in `localStorage`. Events are tagged with `isFancy: true` and `isBookMaker: true`, but the actual Fancy and BookMaker market data is loaded on-demand when navigating to the match detail page.

### Solution

The API now supports **on-demand DOM scraping** via two methods:

1. **`GET /games/:gmid/markets`** — Dedicated endpoint that navigates to the match page and scrapes all markets
2. **`GET /games/:gmid/detail?full=1`** — Existing detail endpoint with `full=1` query param

### Market Types Returned

| Market Type | Key in Response | Description |
|-------------|-----------------|-------------|
| **Match Odds** | `MatchOdds` | Standard 1X2 or win/lose market |
| **BookMaker** | `BookMaker` | Asian-style bookmaker odds |
| **Fancy** | `Fancy` | Session-based bets (runs, wickets, boundaries, etc.) |

### Market Object Structure

```typescript
interface Market {
  name: string;           // "MatchOdds", "BookMaker", or "Fancy"
  minStake: number;       // Minimum bet amount
  maxStake: number;       // Maximum bet amount
  runners: Runner[];
}

interface Runner {
  name: string;           // Team name or fancy runner name
  back: PriceLevel[];     // Back/Yes odds
  lay: PriceLevel[];      // Lay/No odds
  status: "ACTIVE" | "SUSPENDED";
}

interface PriceLevel {
  price: string;          // Odds value (e.g., "6.40", "541")
  size: string;           // Liquidity (e.g., "42k", "2m")
}
```

### Performance Notes

- **Latency**: ~6-10 seconds per request (page navigation + DOM render + scrape)
- **Cache**: Results cached for **15 seconds** to avoid repeated scraping
- **Rate limit**: Don't call more than once every 15 seconds per game
- **Best practice**: Call only when user opens a match detail view

### Example: Scraping Flow

```javascript
// 1. Get game list (fast, cached)
const games = await fetch('/api/v2/diamond/games?password=Lav@9868@');

// 2. When user clicks a game, fetch full markets (slower, on-demand)
const markets = await fetch('/api/v2/diamond/games/5358824/markets?password=Lav@9868@');
```

---

## 6. Casino System In-Depth

### Structure

Casino data is organized as **categories** containing **games**:

```
Casino
├── Lobby (2 games)
│   ├── Aviator (provider: intl, gameCode: spribe_aviator)
│   └── Aura Casino (provider: lotus)
├── Landing (15 games)
│   ├── Ezugi (provider: intl)
│   └── Royal Gaming (provider: intl)
├── TopSlider (6 games)
├── NewSlider (5 games)
├── YoFooter (8 games)
└── ... (12 categories total)
```

### Providers

| Provider | Type | Launch Method |
|----------|------|---------------|
| `intl` | International casino | gameCode + gameId |
| `lotus` | Aura/Aura Casino | Token-based URL |
| `mac` | Mac games | gameCode |
| `internal` | Internal pages | Page path |

### Launching a Casino Game

1. Get `casinoToken` from `/tokens` endpoint
2. Get game details from `/tables` endpoint
3. For **intl** games: Use `gameCode` to launch via provider iframe
4. For **lotus** games: Replace `{token}` in URL with `casinoToken`

**Example:** Aura Casino launch URL:
```
https://aura.fawk.app/{token}/82501
→ https://aura.fawk.app/eyJhbGci.../82501
```

---

## 7. Odds & Calculations

### Back vs Lay

| Type | You | Profit Formula | Loss Formula |
|------|-----|----------------|--------------|
| **Back** | Bet FOR outcome | `stake × (price - 1)` | `stake` |
| **Lay** | Bet AGAINST outcome | `stake` | `stake × (price - 1)` |

### Example: Back Bet

- **Stake:** ₹100
- **Back Price:** 2.50
- **If win:** `100 × (2.50 - 1) = ₹150` profit
- **If lose:** `₹100` loss

### Example: Lay Bet

- **Stake:** ₹100
- **Lay Price:** 2.50
- **If win (outcome DOES NOT happen):** `₹100` profit
- **If lose (outcome HAPPENS):** `100 × (2.50 - 1) = ₹150` loss

### Exposure Calculation

Exposure = Sum of all potential losses across open bets.

```javascript
function calculateExposure(openBets) {
  return openBets.reduce((total, bet) => {
    if (bet.betType === 'Back') {
      return total + bet.stake; // Max loss = stake
    } else {
      return total + bet.expectedLoss; // Max loss = stake × (price - 1)
    }
  }, 0);
}
```

### Liability on Lay

```javascript
function layLiability(stake, price) {
  return stake * (price - 1);
}

// Example: Lay ₹5000 @ 1.50
// Liability = 5000 * (1.50 - 1) = ₹2500
```

---

## 8. Domain Rotation System

### How It Works

The `exchangeDomainPool.js` manages domain health across 176+ exchange domains.

### Health Scoring

```
Score = successRate × healthBonus × recencyBonus

Where:
- successRate = 1 - (failures / totalRequests)
- healthBonus = 1.0 if healthy, 0.1 if in cooldown
- recencyBonus = 1.2 if succeeded in last 5 min, 1.0 otherwise
```

### Cooldown Escalation

| Consecutive Failures | Cooldown Duration |
|---------------------|-------------------|
| 1 | 30 seconds |
| 2 | 2 minutes |
| 3 | 5 minutes |
| 4 | 10 minutes |
| 5+ | 30 minutes |

### Rotation Logic

1. Score all domains
2. Pick highest-scoring **healthy** domain
3. If all domains in cooldown, pick the one with **earliest cooldown expiry**
4. On success: reset consecutive failures, clear cooldown
5. On failure: increment consecutive failures, apply cooldown

### Current Pools

| Pool | Domains | Status |
|------|---------|--------|
| mouseexch | 15 | All dead (DNS/Cloudflare) |
| allpanel | 176+ | All dead (DNS/Cloudflare) |
| imatchodds | 1 (silver247x.com) | ✅ Active |

### Adding Domains at Runtime

```javascript
const domainPool = require('./src/services/exchangeDomainPool');
domainPool.addDomain('imatchodds', 'https://probet777.com');
```

---

## 9. Implementation Guide for Aggregators

### Polling Strategy

| Endpoint | Recommended Interval | Why |
|----------|---------------------|-----|
| `/sports` | 60 seconds | Sports list rarely changes |
| `/games` | 15-20 seconds | Odds change frequently |
| `/highlights` | 15-20 seconds | Live status changes |
| `/games/:gmid/data` | 3-5 seconds | Per-game odds for trading |
| `/open-bets` | 30 seconds | Bet status updates |
| `/tables` | 60 seconds | Casino catalog rarely changes |
| `/status` | 60 seconds | Health monitoring |

### Rate Limiting

- The upstream poller runs every **20 seconds**
- Cache TTL is **60 seconds**
- No explicit rate limits on the API itself
- Recommend: max 1 request per second per endpoint

### Error Handling

```javascript
async function fetchWithRetry(endpoint, retries = 3) {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(`http://145.79.12.201:3001/api/v2/diamond${endpoint}`, {
        headers: { 'x-password': 'Lav@9868@' }
      });
      const data = await res.json();
      if (data.success) return data.data;
      throw new Error(data.error);
    } catch (err) {
      if (i === retries - 1) throw err;
      await sleep(1000 * (i + 1));
    }
  }
}
```

### WebSocket Alternative

Currently Diamond API is REST-only. For real-time updates, poll the `/highlights` or `/games/:gmid/data` endpoints. Future versions may add WebSocket support.

---

## 10. External APIs for Expansion

The following APIs were researched and can be integrated as additional upstreams:

### 9.1 Betfair Exchange API

| | |
|---|---|
| **Base URL** | `https://api.betfair.com/exchange/` |
| **Auth** | App Key + Session Token (OAuth 2.0) |
| **Free Tier** | ✅ Delayed App Key (1s delay, no bet placement) |
| **Live Key** | ✅ Available after account verification |
| **WebSocket** | ✅ Stream API for real-time market data |
| **Cricket** | ✅ Full coverage |
| **Docs** | https://developer.betfair.com/ |

**Key Endpoints:**
- `listEventTypes` — Get all sports
- `listMarketCatalogue` — Get markets for events
- `listMarketBook` — Get live odds + liquidity
- `placeOrders` — Place back/lay bets

**Node.js Library:** `felixmccuaig/betfair-node` (TypeScript, Stream API support)

### 9.2 BetInAsia BLACK API

| | |
|---|---|
| **Type** | WebSocket Push API |
| **Auth** | API Key (contact sales) |
| **Free Tier** | ❌ No free tier |
| **Coverage** | 10+ Asian bookmakers + 6 exchanges |
| **Exchanges** | Betfair, Betdaq, MollyBet, SMarkets, Matchbook, Betdex |
| **Docs** | https://betinasia.com/sports-betting-api/ |

**Features:**
- Asynchronous push via persistent WebSocket
- Live betslips, open orders, events, prices
- Algorithmic betting bot support

### 9.3 The Odds API

| | |
|---|---|
| **Base URL** | `https://api.the-odds-api.com/v4/` |
| **Auth** | API Key |
| **Free Tier** | ✅ 25 requests/day |
| **Paid Tier** | $29-299/month |
| **Coverage** | 30+ bookmakers, 20+ sports |
| **Cricket** | ✅ |
| **Docs** | https://the-odds-api.com/ |

**Key Endpoints:**
- `/sports` — List sports
- `/sports/{sport}/odds` — Get odds for sport
- `/sports/{sport}/scores` — Live scores

**Best for:** Odds comparison, arbitrage detection

### 9.4 API-FOOTBALL

| | |
|---|---|
| **Base URL** | `https://v3.football.api-sports.io/` |
| **Auth** | `x-apisports-key` header |
| **Free Tier** | ✅ 100 requests/day |
| **Coverage** | 1,200+ leagues, live scores, lineups, odds |
| **Cricket** | ❌ Football only |
| **Docs** | https://www.api-football.com/ |

**Key Endpoints:**
- `/leagues` — All leagues
- `/fixtures` — Match schedule + live status
- `/odds` — Pre-match odds
- `/predictions` — AI predictions

### 9.5 Cricbuzz (via RapidAPI)

| | |
|---|---|
| **Base URL** | `https://cricbuzz-cricket.p.rapidapi.com/` |
| **Auth** | RapidAPI Key (`x-rapidapi-key`) |
| **Free Tier** | ✅ $0 tier (limited calls) |
| **Coverage** | IPL, international, domestic cricket |
| **Data** | Scores, commentary, stats, schedules |
| **Docs** | https://rapidapi.com/apidojo/api/cricbuzz-cricket |

**Key Endpoints:**
- `/matches/v1/recent` — Recent matches
- `/matches/v1/live` — Live matches
- `/stats/v1/series/...` — Series stats

### Comparison Table

| API | Free Tier | Betting | Live Odds | WebSocket | Cricket | Ease |
|-----|-----------|---------|-----------|-----------|---------|------|
| **Betfair** | ✅ Delayed | ✅ | ✅ | ✅ Stream | ✅ | Medium |
| **BetInAsia** | ❌ | ✅ | ✅ | ✅ Push | ✅ | Hard |
| **The Odds API** | ✅ 25/day | ❌ | ✅ | ❌ | ✅ | Easy |
| **API-FOOTBALL** | ✅ 100/day | ❌ | ✅ | ❌ | ❌ | Easy |
| **Cricbuzz** | ✅ | ❌ | ❌ | ❌ | ✅ | Easy |

---

## 11. Code Examples

### JavaScript / Node.js

```javascript
const BASE_URL = 'http://145.79.12.201:3001/api/v2/diamond';
const PASSWORD = 'Lav@9868@';

async function getLiveGames() {
  const res = await fetch(`${BASE_URL}/highlights`, {
    headers: { 'x-password': PASSWORD }
  });
  const data = await res.json();
  return data.data.inplay; // Array of live games
}

async function getGameOdds(gmid) {
  const res = await fetch(`${BASE_URL}/games/${gmid}/data`, {
    headers: { 'x-password': PASSWORD }
  });
  const data = await res.json();
  return data.data.game.runners;
}

// Usage
const games = await getLiveGames();
for (const game of games) {
  console.log(`${game.title}: ${game.status}`);
  for (const runner of game.runners) {
    const back = runner.back[0]?.price || '-';
    const lay = runner.lay[0]?.price || '-';
    console.log(`  ${runner.name}: Back ${back} / Lay ${lay}`);
  }
}
```

### Python

```python
import requests

BASE_URL = 'http://145.79.12.201:3001/api/v2/diamond'
HEADERS = {'x-password': 'Lav@9868@'}

def get_live_games():
    r = requests.get(f'{BASE_URL}/highlights', headers=HEADERS)
    return r.json()['data']['inplay']

def get_game_odds(gmid):
    r = requests.get(f'{BASE_URL}/games/{gmid}/data', headers=HEADERS)
    return r.json()['data']['game']['runners']

def calculate_lay_liability(stake, price):
    return stake * (price - 1)

# Usage
games = get_live_games()
for game in games:
    print(f"{game['title']}: {game['status']}")
    for runner in game['runners']:
        back = runner['back'][0]['price'] if runner['back'] else '-'
        lay = runner['lay'][0]['price'] if runner['lay'] else '-'
        print(f"  {runner['name']}: Back {back} / Lay {lay}")
```

### cURL

```bash
# Get all sports
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/sports"

# Get cricket games
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/games?sport_id=3"

# Get game odds
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/games/5359254/data"

# Get open bets
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/open-bets"

# Get casino
curl -H "x-password: Lav@9868@" \
  "http://145.79.12.201:3001/api/v2/diamond/tables"
```

---

## 12. Troubleshooting

### "Unauthorized" Response
- Ensure `x-password: Lav@9868@` header or `?password=Lav@9868@` query param is present
- Header method is preferred

### Empty Games List
- Check `/status` to see if poller is running
- If `imatchodds` shows 0 games, the upstream may be temporarily unreachable
- Wait 20-30 seconds for next poll cycle

### "Game not found" Error
- The game ID may have changed or the match may have ended
- Use `/games` or `/highlights` to get current valid game IDs

### Stale Odds
- Odds are cached for up to 60 seconds
- For real-time trading, poll every 3-5 seconds
- The upstream itself polls every 20 seconds

### Scorecard Not Available
- Not all games have score iframes
- Check `videoURL` field in the game object
- Test `/games/:gmid/scorecard` endpoint

### Casino Games Not Loading
- Casino requires `casinoToken` from `/tokens` endpoint
- Tokens expire — refresh before launching games
- Some providers require specific domains (aura.fawk.app, etc.)

### Domain Pool All Dead
- If all upstreams show 0 games, check `/status`
- The `imatchodds` upstream uses a single domain (silver247x.com)
- If silver247x.com is blocked, the system will retry with fresh browser sessions

---

## Appendix A: Sport IDs

| ID | Name |
|----|------|
| 1 | Football |
| 2 | Tennis |
| 3 | Cricket |
| 26 | Horse Racing |

---

## Appendix B: Upstream Sources

### imatchodds (silver247x.com)
- **Type:** Vue 3 SPA with localStorage data
- **Auth:** Demo login (no credentials needed)
- **Poll Interval:** 20 seconds
- **Data:** Sports, events, back/lay odds, casino, open bets, userinfo
- **Status:** ✅ Active

### mouseexch / allpanel (Disabled)
- **Type:** EcoAssets v103 (AES-encrypted API)
- **Status:** ❌ All domains dead (DNS resolution failed, Cloudflare blocked)
- **Note:** Kept in codebase for future reactivation if working domains are found

---

## Appendix C: Roadmap — Legacy API Parity

The legacy skyprovider aggregator (`/api/v2/events`, `/api/v2/bets`, `/api/v2/settlements`) used **mouseexch + allpanel + skyprovider (uni247)** with smart domain rotation. Those upstreams are now dead.

**Diamond API is the replacement**, using **imatchodds** (silver247x.com) as the sole live upstream.

### What Exists in Diamond ✅

| Feature | Legacy Endpoint | Diamond Endpoint |
|---------|-----------------|-----------------|
| Sports list | `GET /sports` | ✅ `GET /diamond/sports` |
| Events list | `GET /events` | ✅ `GET /diamond/games` |
| Event detail | `GET /events/:id` | ✅ `GET /diamond/games/:gmid/detail` |
| Live odds | `GET /events/:id/odds` | ✅ `GET /diamond/games/:gmid/markets` |
| Fancy odds | `GET /events/:id/fancy` | ✅ `GET /diamond/games/:gmid/markets` |
| Scorecard | `GET /events/:id/scorecard` | ✅ `GET /diamond/games/:gmid/scorecard` |
| Live TV | `GET /events/:id/live-tv` | ✅ `GET /diamond/games/:gmid/live-tv` |
| Highlights | `GET /highlights` | ✅ `GET /diamond/highlights` |

### What's Missing ❌ (Priority Order)

| Priority | Feature | Legacy Endpoint | Status |
|----------|---------|-----------------|--------|
| 🔴 | **Search games** | `GET /events/search` | Not implemented |
| 🔴 | **Dedicated odds endpoint** | `GET /events/:id/odds` | Partial (use `/markets`) |
| 🔴 | **Bet placement** | `POST /bets` | Not implemented |
| 🔴 | **Settlement preview** | `POST /settlements/preview` | Not implemented |
| 🟡 | **Odds history** | `GET /events/:id/odds/history` | Not implemented |
| 🟡 | **Bet listing** | `GET /bets` | Not implemented |
| 🟡 | **Auto-settlement** | `POST /settlements/auto` | Not implemented |
| 🟡 | **Bulk settlement** | `POST /settlements/bulk` | Not implemented |
| 🟡 | **Bet trace** | `GET /trace/*` | Not implemented |
| 🟢 | **Real-time streaming** | WebSocket | Not implemented (20s poll) |

### Why mouseexch/allpanel Are Dead

The **smart login rotation** system (`exchangeDomainPool.js`) tracked 15 mouseexch + ~200 allpanel domains with health scoring and cooldown logic. All domains now fail with:
- DNS resolution errors
- Cloudflare 403 blocks
- Connection timeouts

The domain rotation code still exists but has **zero healthy domains** to rotate to.

### Full Comparison Document

See `LEGACY_VS_DIAMOND.md` for a complete side-by-side endpoint mapping.

---

*End of Diamond API Documentation*
