Skip to main content

Roanuz Cricket API — Inventory & Audit (2026-05-14)

Companion to the local-only roanuz-api-inspector skill (.claude/skills/roanuz-api-inspector/). This file is the committed, reviewable source of truth; the skill is the operational tool that ties it to live SSH commands. Keep them in sync.

Why this exists

On 2026-05-14, the Strykr UI showed PBKS as 0/0 (17.3) STRUCK against MI 40/0 (4.2) LIVE during an IPL 2026 fixture, with caption "Mumbai Indians needs 161 off 94 balls" — an internally contradictory state. A target of 161 implies PBKS scored 160; the UI showed 0. This document captures the audit that traced the bug to adapter path mismatches, not provider data loss.

TL;DR

  • Roanuz is sending correct data. PBKS at 200 confirmed via /match/{id}/ and /match/{id}/worm/ against the same fixture.
  • The adapter reads the wrong paths. Five distinct bugs in RoanuzDataAdapter.ts + RoanuzWebSocketManager.ts produce the symptoms.
  • Sample responses (live captures) are in ./sample-responses/. Eight endpoints total: 5 return 200, 2 return 403, 1 returns 404.

Service surface

  • REST base URL: https://api.sports.roanuz.com
  • Socket.IO URL: https://socket.sports.roanuz.com/cricket
  • Auth: JWT-style token, ~5 min TTL, obtained by exchanging ROANUZ_API_KEY at /v5/core/{key}/auth/. Header on subsequent calls: rs-token.
  • Server env file: backend/.env on strykrdev / strykrprod. Required vars: ROANUZ_API_KEY, ROANUZ_PROJECT_KEY, optional ROANUZ_BASE_URL.
  • Adapter code: backend/src/exchanges/adapters/roanuz/RoanuzDataAdapter.ts (REST), RoanuzWebSocketManager.ts (Socket.IO).

REST endpoint table

#EndpointStatusSampleAdapter
1GET /v5/cricket/{key}/featured-matches-2/200 ✓featured-matches-2.jsongetMatches line 263
2GET /v5/cricket/{key}/match/{id}/200 ✓match-detail.jsongetMatchState line 354
3GET /v5/cricket/{key}/match/{id}/ball-by-ball/{over}/200 ✓ball-by-ball.jsongetBallByBall line 398
4GET /v5/cricket/{key}/match/{id}/worm/200 ✓worm.jsongetWormData line 875
5GET /v5/cricket/{key}/match/{id}/run-rate/200 ✓run-rate.jsongetRunRateData line 922
6GET /v5/cricket/{key}/tournament/{id}/fixtures/403fixtures-403.jsongetSchedule line 660
7GET /v5/cricket/{key}/match/{id}/commentary/403commentary-403.jsongetCommentary line 595
8GET /v5/cricket/{key}/match/{id}/scorecard/404scorecard-404.jsongetScorecard line 618

403 = our project key lacks that entitlement. 404 = the path is stale or moved. All three error responses are silently swallowed by the adapter — no log lines, no metrics.

Response shapes (the parts that matter)

The full sample JSONs are in ./sample-responses/. The fields the adapter must read correctly:

Endpoint 2 — /match/{id}/ (the bug epicenter)

{
"data": {
"play": { // ← state lives under `play`, NOT at root
"innings": { // dict, NOT array
"a_1": {
"score": { "runs": 200, "wickets": 7, "overs": 20.0, "balls": 120 }
},
"b_1": { "score": { "runs": 40, "wickets": 0, "overs": 4.2 } }
},
"live": {
"innings_number": 2,
"score": { "runs": 40, "wickets": 0, "overs": 4.2 },
"required_run_rate": 8.50,
"current_run_rate": 9.40
},
"target": { // ← under `play.target`, NOT `data.target`
"runs": 201, "overs": 20.0, "required_run_rate": 8.50
}
}
}
}

Endpoint 4 — /worm/ (independent verification)

{ "data": { "x": [1..20], "y": [
[7,16,21,31,46,55,58,67,76,89,100,111,122,128,135,140,147,166,188,200],
[4,12,21,31,40]
] } }

data.y[0] ending at 200 confirms PBKS scored 200 — independently of endpoint 2.

Adapter bugs found

Full snippets and fix sketches in the skill at .claude/skills/roanuz-api-inspector/references/adapter_bugs.md.

BugFile:LineClassUI effect
ARoanuzDataAdapter.ts:1167Reads data.innings not data.play.inningsinnings list always []
BRoanuzDataAdapter.ts:1156-1159score.runs || 0 etc.score reads 0/0/0 — also violates financial-security.md §1.2
CRoanuzWebSocketManager.ts:759innings?.[N-1] on a dictlive updates silently no-op
DRoanuzDataAdapter.ts:1244Reads data.target not data.play.targettarget/RRR always undefined
Eadapter-wideToss has raw-response log (line 1182); score does notforensic blind spot

Plus secondary issues: 403/404 endpoints fail silently; no per-endpoint metrics; token cache doesn't invalidate on 401.

Socket.IO surface

DirectionEventNotes
outboundjoin_matchSubscribe to a match
outboundleave_matchUnsubscribe
inboundon_match_joinedFull snapshot, same shape as /match/{id}/
inboundon_match_updateDeltas: ball_by_ball, wicket, over_complete, innings_change, match_end
inboundon_errorProvider error

Subscribed events (adapter line 134): ['ball_by_ball', 'wicket', 'over_complete', 'innings_change', 'match_end'].

Cache keys (Redis)

KeyTypeTTLPurpose
roanuz:state:<matchId>string (JSON)30sNormalized match state — currently stores wrong values per Bug A/B
roanuz:fixtures:livesetevent-drivenLive match IDs
roanuz:mg100:*string60sAggregated chart data
roanuz:tokenstring~5 minBearer token

Cache is downstream of the adapter — flushing won't fix the bugs. The bugs are in the read/normalize path before the cache write.

  1. Fix Bug A and B together. They're causally linked and B masks A's diagnostic value.
  2. Fix Bug D alongside A/B (independent but small).
  3. Fix Bug C in a separate PR — WS path has higher blast radius.
  4. Add Bug E logging as a forensic precondition; can ship before fixes.
  5. Decide whether to upgrade Roanuz plan to unlock endpoints 6 & 7 (fixtures, commentary), or accept the 403s as permanent and remove the dead calls.

How to verify these claims yourself

Use the local-only skill: /roanuz-api-inspector prod verify <matchId>. Or run the inline commands from .claude/skills/roanuz-api-inspector/SKILL.md against any in-play IPL fixture.

What this PR contains

  • docs/roanuz/api-inventory.md — this file
  • docs/roanuz/sample-responses/*.json — 8 raw responses captured from prod on 2026-05-14

The matching skill (.claude/skills/roanuz-api-inspector/) is gitignored (per .gitignore .claude/* rule) and lives locally on each engineer's machine.