dubs-server 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) hide show
  1. package/.claude/settings.local.json +280 -0
  2. package/CLAUDE.md +46 -0
  3. package/CONNECT4_PRODUCTION_DEPLOY.md +155 -0
  4. package/CURRENT_SESSION.md +171 -0
  5. package/CURRENT_SESSION_DRAW.md +516 -0
  6. package/MARCH_MADNESS_SURVIVOR.md +254 -0
  7. package/PANDA.md +166 -0
  8. package/Procfile +4 -0
  9. package/README.md +476 -0
  10. package/controllers/livescoresController.js +376 -0
  11. package/controllers/pickemController.js +554 -0
  12. package/controllers/survivorAdminController.js +887 -0
  13. package/controllers/survivorController.js +623 -0
  14. package/cron/oracleMonitor.js +77 -0
  15. package/cron/pickemOracleMonitor.js +73 -0
  16. package/data/jackpot-history.json +952 -0
  17. package/data/ncaaTeams.js +406 -0
  18. package/documentation/API_SECURITY_GUIDE.md +327 -0
  19. package/documentation/ARCADE_API.md +593 -0
  20. package/documentation/ARCADE_IMPLEMENTATION_SUMMARY.md +399 -0
  21. package/documentation/ARCADE_QUICKSTART.md +242 -0
  22. package/documentation/AUTOMATIC_MODE_ORACLE.md +321 -0
  23. package/documentation/BUG_FIX_COHORT_DATE_DISPLAY.md +171 -0
  24. package/documentation/CLAIM_MIGRATION_INSTRUCTIONS.md +52 -0
  25. package/documentation/CLAIM_STATUS_FIX.md +67 -0
  26. package/documentation/CLI_TOOL_GUIDE.md +372 -0
  27. package/documentation/COHORT_RETENTION_ANALYSIS.md +295 -0
  28. package/documentation/COHORT_RETENTION_IMPLEMENTATION_COMPLETE.md +461 -0
  29. package/documentation/COHORT_RETENTION_SUMMARY.md +204 -0
  30. package/documentation/COMPLETE_PROJECT_SUMMARY.md +490 -0
  31. package/documentation/DATABASE_QUERIES.md +269 -0
  32. package/documentation/DATABASE_RETENTION_POLICY.md +390 -0
  33. package/documentation/DATABASE_SETUP_GUIDE.md +361 -0
  34. package/documentation/DATABASE_SETUP_SUMMARY.md +247 -0
  35. package/documentation/DEMO_API_CURL_COMMANDS.md +656 -0
  36. package/documentation/DEPLOYMENT_SUMMARY.txt +100 -0
  37. package/documentation/DUPLICATE_NOTIFICATIONS_FIXED.md +201 -0
  38. package/documentation/EXCHANGE_RATES_INTEGRATION.md +371 -0
  39. package/documentation/FINAL_API_PROTECTION_TABLE.md +175 -0
  40. package/documentation/GAME_START_NOTIFICATIONS_DEPLOYMENT.md +256 -0
  41. package/documentation/GAME_START_NOTIFICATIONS_INTEGRATION.md +275 -0
  42. package/documentation/HEROKU_DEPLOYMENT.md +134 -0
  43. package/documentation/HEROKU_SCHEDULER_SETUP.md +271 -0
  44. package/documentation/JACKPOT_API.md +521 -0
  45. package/documentation/JACKPOT_DEPLOYMENT_GUIDE.md +362 -0
  46. package/documentation/JWT_IMPLEMENTATION_SUMMARY.md +373 -0
  47. package/documentation/JWT_QUICK_SETUP.md +268 -0
  48. package/documentation/JWT_TESTING_GUIDE.md +404 -0
  49. package/documentation/KEEPER_RECOVERY_GUIDE.md +381 -0
  50. package/documentation/KEEPER_SETUP.md +206 -0
  51. package/documentation/KEEPER_STATE_MACHINE.md +423 -0
  52. package/documentation/LATEST_PRODUCTION_SETUP.md +387 -0
  53. package/documentation/LOCAL_VOTING_TEST.md +279 -0
  54. package/documentation/ORACLE_FIXES_SUMMARY.md +188 -0
  55. package/documentation/ORACLE_POSTGRESQL_UPDATE.md +202 -0
  56. package/documentation/PAYMENT_DEPLOYMENT.md +209 -0
  57. package/documentation/PNL_TRACKING_SETUP.md +189 -0
  58. package/documentation/PREVENTING_LOCKUP_ERRORS.md +472 -0
  59. package/documentation/PRODUCTION_READY_SUMMARY.md +227 -0
  60. package/documentation/PUBLIC_VS_PRIVATE_ENDPOINTS.md +278 -0
  61. package/documentation/QUICK_AUTH_SETUP.md +99 -0
  62. package/documentation/QUICK_DEPLOY.md +224 -0
  63. package/documentation/QUICK_FIX.md +114 -0
  64. package/documentation/QUICK_START.md +152 -0
  65. package/documentation/REFEREE_MODE_GUIDE.md +392 -0
  66. package/documentation/RETENTION_CORE_ACTION_UPDATE.md +313 -0
  67. package/documentation/RETENTION_UPDATE_SUMMARY.md +108 -0
  68. package/documentation/RUN_MIGRATION_NOW.md +39 -0
  69. package/documentation/SCRIPTS_UPDATE_SUMMARY.md +251 -0
  70. package/documentation/SETUP_GUIDE.md +184 -0
  71. package/documentation/STATE_MACHINE_IMPLEMENTATION.md +250 -0
  72. package/documentation/TELEGRAM_NOTIFICATIONS_DIAGNOSIS.md +361 -0
  73. package/documentation/UNIFIED_ARCHITECTURE.md +231 -0
  74. package/documentation/VOTING_DEPLOYMENT_SUMMARY.md +392 -0
  75. package/documentation/WEBSOCKET_ARCHITECTURE.md +881 -0
  76. package/documentation/WHAT_WE_BUILT_TODAY.md +369 -0
  77. package/documentation/latest/LATEST_PRODUCTION_SETUP.md +865 -0
  78. package/ecosystem.config.js +65 -0
  79. package/env.template +125 -0
  80. package/middleware/apiKeyAuth.js +136 -0
  81. package/middleware/authenticate.js +214 -0
  82. package/middleware/developerUserAuth.js +76 -0
  83. package/middleware/socketAuth.js +69 -0
  84. package/package.json +49 -0
  85. package/postman/Dubs-API-v1-With-Voting.postman_collection.json +555 -0
  86. package/postman/Dubs-API-v1.postman_collection.json +205 -0
  87. package/postman/Dubs_Developer_API.postman_collection.json +662 -0
  88. package/postman/QUICKSTART.md +118 -0
  89. package/postman/QUICK_REFERENCE.md +246 -0
  90. package/postman/README.md +71 -0
  91. package/postman/VOTING_API_GUIDE.md +426 -0
  92. package/refactor/Animations.md +148 -0
  93. package/refactor/Chat.md +252 -0
  94. package/routes/actionsRoutes.js +699 -0
  95. package/routes/adminRoutes.js +370 -0
  96. package/routes/analyticsRoutes.js +1262 -0
  97. package/routes/arcadeRoutes.js +557 -0
  98. package/routes/authRoutes.js +2310 -0
  99. package/routes/avatarRoutes.js +85 -0
  100. package/routes/botRoutes.js +211 -0
  101. package/routes/chatRoutes.js +377 -0
  102. package/routes/cryptoPriceRoutes.js +105 -0
  103. package/routes/developerRoutes.js +4201 -0
  104. package/routes/deviceRoutes.js +214 -0
  105. package/routes/dmRoutes.js +167 -0
  106. package/routes/esportsRoutes.js +806 -0
  107. package/routes/exchangeRateRoutes.js +233 -0
  108. package/routes/gamesRoutes.js +3028 -0
  109. package/routes/jackpotRoutes.js +754 -0
  110. package/routes/keeperMonitoringRoutes.js +156 -0
  111. package/routes/keeperWebhookRoutes.js +466 -0
  112. package/routes/livescoresRoutes.js +31 -0
  113. package/routes/pickemAdminRoutes.js +199 -0
  114. package/routes/pickemRoutes.js +231 -0
  115. package/routes/playerStatsRoutes.js +147 -0
  116. package/routes/portfolioRoutes.js +217 -0
  117. package/routes/promoRoutes.js +418 -0
  118. package/routes/referralEarningsRoutes.js +392 -0
  119. package/routes/socialRoutes.js +459 -0
  120. package/routes/sportsRoutes.js +1271 -0
  121. package/routes/survivorAdminRoutes.js +345 -0
  122. package/routes/survivorRoutes.js +756 -0
  123. package/routes/uploadRoutes.js +256 -0
  124. package/routes/userProfileRoutes.js +244 -0
  125. package/routes/whatsNewRoutes.js +331 -0
  126. package/scripts/.claude/settings.local.json +15 -0
  127. package/scripts/README.md +170 -0
  128. package/scripts/RESTART_EVERYTHING.sh +104 -0
  129. package/scripts/add-claim-columns.sql +48 -0
  130. package/scripts/add-crypto-prices-cache.sql +27 -0
  131. package/scripts/add-exchange-rates-cache.sql +40 -0
  132. package/scripts/add-game-invite-column.sql +23 -0
  133. package/scripts/add-game-invite-notification.sql +33 -0
  134. package/scripts/add-game-invite-telegram-pref.sql +16 -0
  135. package/scripts/add-game-joined-notification.sql +16 -0
  136. package/scripts/add-game-joined-pref.js +40 -0
  137. package/scripts/add-game-joined-preference.sql +6 -0
  138. package/scripts/add-game-start-notifications.sql +41 -0
  139. package/scripts/add-notification-flags-to-games.sql +55 -0
  140. package/scripts/add-pending-game-dismissals.sql +19 -0
  141. package/scripts/add-preferred-currency.sql +34 -0
  142. package/scripts/add-winner-columns.js +61 -0
  143. package/scripts/add_mention_system.sql +53 -0
  144. package/scripts/add_payment_system.sql +96 -0
  145. package/scripts/add_sports_event_id_column.sql +22 -0
  146. package/scripts/analyze-cohort-data-heroku.js +276 -0
  147. package/scripts/analyze-cohort-data.js +295 -0
  148. package/scripts/analyze-prod-cohorts.sh +10 -0
  149. package/scripts/backfill-matchup-images.js +245 -0
  150. package/scripts/backfill-missing-signatures.js +175 -0
  151. package/scripts/backfill-referral-earnings.js +202 -0
  152. package/scripts/check-chat-schema.js +130 -0
  153. package/scripts/check-db.sh +14 -0
  154. package/scripts/check_oracle_in_game.js +54 -0
  155. package/scripts/cleanup-database.js +193 -0
  156. package/scripts/clear-notification-cache.js +85 -0
  157. package/scripts/convert-mnemonic.js +50 -0
  158. package/scripts/create-users-table.sql +44 -0
  159. package/scripts/debug-cohort-counts.js +248 -0
  160. package/scripts/debug-winner-calc.js +84 -0
  161. package/scripts/deploy-payment-system.sh +118 -0
  162. package/scripts/deploy-to-heroku.sh +63 -0
  163. package/scripts/diagnose-locked-round.js +143 -0
  164. package/scripts/dubs-cli.js +720 -0
  165. package/scripts/dump-account.js +65 -0
  166. package/scripts/find-vrf-offset.js +48 -0
  167. package/scripts/fix-chat-notifications-constraint.sql +122 -0
  168. package/scripts/fix-claim-columns.js +124 -0
  169. package/scripts/fix-constraint-now.js +44 -0
  170. package/scripts/fix-lock-timestamps.js +96 -0
  171. package/scripts/fix-locked-round.sh +126 -0
  172. package/scripts/fix-missing-badges.sql +91 -0
  173. package/scripts/fix-payment-notifications.sql +41 -0
  174. package/scripts/force-new-round.js +55 -0
  175. package/scripts/force-resolve-and-claim.js +278 -0
  176. package/scripts/important/README.md +115 -0
  177. package/scripts/important/authority-force-lock.js +197 -0
  178. package/scripts/important/authority-resolve-game.js +267 -0
  179. package/scripts/important/check-game-status.js +373 -0
  180. package/scripts/important/list-pending-games-by-version.js +270 -0
  181. package/scripts/important/reconcile-v1-v2-payouts.js +270 -0
  182. package/scripts/initialize-jackpot.js +111 -0
  183. package/scripts/jackpot/.claude/settings.local.json +10 -0
  184. package/scripts/jackpot/force-reset.js +84 -0
  185. package/scripts/jackpot/initialize-mainnet.js +100 -0
  186. package/scripts/jackpot/keeper.js +742 -0
  187. package/scripts/jackpot/status.js +107 -0
  188. package/scripts/jackpot/update-round-duration.js +143 -0
  189. package/scripts/keeper-bot.js +112 -0
  190. package/scripts/list-pending-games.js +131 -0
  191. package/scripts/migrate-chat-v2.js +127 -0
  192. package/scripts/migrate-chat-winners.js +84 -0
  193. package/scripts/migrate-chat.sh +17 -0
  194. package/scripts/migrate-game-invite.js +83 -0
  195. package/scripts/migrate-heroku-game-notifications.sh +159 -0
  196. package/scripts/migrations/001_analytics_tables.sql +422 -0
  197. package/scripts/migrations/002_add_matchup_image_url.sql +14 -0
  198. package/scripts/migrations/003_referral_earnings.sql +208 -0
  199. package/scripts/migrations/004_add_whats_new_notification_type.sql +62 -0
  200. package/scripts/migrations/005_add_connect4_your_turn_notification.sql +61 -0
  201. package/scripts/migrations/005_push_notifications.sql +55 -0
  202. package/scripts/migrations/006_add_draw_team_players.sql +28 -0
  203. package/scripts/migrations/006_add_game_cancelled_notification.sql +62 -0
  204. package/scripts/migrations/007_add_gif_url.sql +8 -0
  205. package/scripts/migrations/008_add_connect4_columns.sql +139 -0
  206. package/scripts/migrations/008_add_pool_tracking.sql +22 -0
  207. package/scripts/migrations/009_create_survivor_pool_tables.sql +174 -0
  208. package/scripts/migrations/010_add_survivor_pool_outcome.sql +28 -0
  209. package/scripts/migrations/011_create_developer_tables.sql +67 -0
  210. package/scripts/migrations/011_fix_keeper_tables.sql +85 -0
  211. package/scripts/migrations/012_create_developer_webhooks.sql +31 -0
  212. package/scripts/migrations/013_add_network_mode.sql +18 -0
  213. package/scripts/migrations/014_create_developer_app_users.sql +19 -0
  214. package/scripts/migrations/015_add_ui_config.sql +4 -0
  215. package/scripts/migrations/016_add_resolution_secret.sql +4 -0
  216. package/scripts/migrations/017_add_external_game_id.sql +3 -0
  217. package/scripts/migrations/018_create_pickem_tables.sql +115 -0
  218. package/scripts/migrations/019_expo_push_tokens.sql +19 -0
  219. package/scripts/migrations/create_whats_new_tables.sql +88 -0
  220. package/scripts/migrations/drop_live_games_tables.sql +34 -0
  221. package/scripts/open-jackpot-round.js +85 -0
  222. package/scripts/purge-all-data.sh +329 -0
  223. package/scripts/purge-all-data.sql +142 -0
  224. package/scripts/purge-heroku-data.sh +149 -0
  225. package/scripts/purge-heroku-data.sql +62 -0
  226. package/scripts/rebuild-heroku-database.sh +113 -0
  227. package/scripts/recover-funds.js +357 -0
  228. package/scripts/regenerate-epl-images.js +278 -0
  229. package/scripts/resize-s3-matchup-images.js +374 -0
  230. package/scripts/resolve-direct.js +88 -0
  231. package/scripts/resolve-mock-game.js +124 -0
  232. package/scripts/resolve-pickem-game.js +55 -0
  233. package/scripts/resolve-round-manual.js +83 -0
  234. package/scripts/resolve-stuck-game.js +382 -0
  235. package/scripts/resolve-stuck-round.js +42 -0
  236. package/scripts/run-connect4-migration.sh +16 -0
  237. package/scripts/run-mention-migration.sh +32 -0
  238. package/scripts/run-payment-migration.sh +51 -0
  239. package/scripts/run-preferred-currency-migration.sh +31 -0
  240. package/scripts/run-referral-earnings-migration.sh +32 -0
  241. package/scripts/run-survivor-outcome-migration.sh +16 -0
  242. package/scripts/seed-test-users.js +346 -0
  243. package/scripts/setup-auth-tables.js +78 -0
  244. package/scripts/setup-complete-database.sql +992 -0
  245. package/scripts/setup-database-fresh.sh +359 -0
  246. package/scripts/setup-heroku-keeper.sh +48 -0
  247. package/scripts/setup-keeper-database.js +83 -0
  248. package/scripts/setup-keeper-state-db.sql +110 -0
  249. package/scripts/setup-oracle.sh +39 -0
  250. package/scripts/setup-pnl-tracking.js +111 -0
  251. package/scripts/start-devnet.sh +14 -0
  252. package/scripts/test-arcade-devnet.sh +160 -0
  253. package/scripts/test-arcade-match.sh +109 -0
  254. package/scripts/test-automatic-mode.sh +239 -0
  255. package/scripts/test-connect4-cancel-claim.js +370 -0
  256. package/scripts/test-connect4-e2e.js +369 -0
  257. package/scripts/test-connect4-resolve.js +369 -0
  258. package/scripts/test-game-state-endpoint.js +136 -0
  259. package/scripts/test-invite-notification.js +86 -0
  260. package/scripts/test-jackpot-api.sh +71 -0
  261. package/scripts/test-poll-confirmation.js +267 -0
  262. package/scripts/test-resolve-game.js +271 -0
  263. package/scripts/test-resolve-signature.js +223 -0
  264. package/scripts/test-signature-preservation.js +124 -0
  265. package/scripts/test-state-machine.js +291 -0
  266. package/scripts/test-webhook-receiver.js +60 -0
  267. package/scripts/update-notification-constraint.js +52 -0
  268. package/scripts/verify-account-layout.js +145 -0
  269. package/scripts/verify-winner-algorithm.js +278 -0
  270. package/server.js +5259 -0
  271. package/services/arcadeMatchService.js +763 -0
  272. package/services/automaticGameOracle.js +1596 -0
  273. package/services/chatService.js +1612 -0
  274. package/services/connect4GameService.js +1049 -0
  275. package/services/connect4NotificationService.js +374 -0
  276. package/services/cryptoPriceService.js +223 -0
  277. package/services/customGameResolver.js +260 -0
  278. package/services/db.js +79 -0
  279. package/services/directMessageService.js +389 -0
  280. package/services/discordNotifications.js +160 -0
  281. package/services/exchangeRateService.js +289 -0
  282. package/services/expoPushService.js +314 -0
  283. package/services/gamesCacheService.js +539 -0
  284. package/services/jackpotHistory.js +331 -0
  285. package/services/jackpotService.js +856 -0
  286. package/services/keeperStateService.js +355 -0
  287. package/services/matchupImageService.js +591 -0
  288. package/services/notificationCacheService.js +407 -0
  289. package/services/pickemOracle.js +440 -0
  290. package/services/playerStatsService.js +389 -0
  291. package/services/portfolioService.js +555 -0
  292. package/services/promoService.js +757 -0
  293. package/services/promoTreasuryService.js +239 -0
  294. package/services/pushNotifications.js +353 -0
  295. package/services/redisService.js +422 -0
  296. package/services/referralEarningsService.js +728 -0
  297. package/services/s3Service.js +396 -0
  298. package/services/socialService.js +1202 -0
  299. package/services/survivorOracle.js +469 -0
  300. package/services/survivorSimulator.js +475 -0
  301. package/services/telegramNotifications.js +461 -0
  302. package/services/userProfileStatsService.js +1185 -0
  303. package/services/whatsNewService.js +388 -0
  304. package/utils/urlHelper.js +95 -0
@@ -0,0 +1,662 @@
1
+ {
2
+ "info": {
3
+ "name": "Dubs Developer API",
4
+ "description": "Dubs Developer API — third-party integration for sports & esports betting on Solana.\n\nTwo sections:\n1. **Portal** (`/api/developer`) — JWT auth, developer account/app/key management\n2. **Public API** (`/api/developer/v1`) — API key auth (`X-API-Key` header), game lifecycle & event data",
5
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
6
+ },
7
+ "variable": [
8
+ {
9
+ "key": "baseUrl",
10
+ "value": "http://localhost:3001",
11
+ "type": "string"
12
+ },
13
+ {
14
+ "key": "apiKey",
15
+ "value": "dubs_test_REPLACE_ME",
16
+ "type": "string"
17
+ },
18
+ {
19
+ "key": "jwtToken",
20
+ "value": "REPLACE_ME",
21
+ "type": "string"
22
+ },
23
+ {
24
+ "key": "appId",
25
+ "value": "1",
26
+ "type": "string"
27
+ },
28
+ {
29
+ "key": "webhookId",
30
+ "value": "1",
31
+ "type": "string"
32
+ },
33
+ {
34
+ "key": "keyId",
35
+ "value": "1",
36
+ "type": "string"
37
+ },
38
+ {
39
+ "key": "gameId",
40
+ "value": "REPLACE_ME",
41
+ "type": "string"
42
+ },
43
+ {
44
+ "key": "playerWallet",
45
+ "value": "REPLACE_ME",
46
+ "type": "string"
47
+ }
48
+ ],
49
+ "item": [
50
+ {
51
+ "name": "Portal (JWT Auth)",
52
+ "description": "Developer portal management routes. Requires JWT auth via `Authorization: Bearer <token>`. Mounted at `/api/developer`.",
53
+ "item": [
54
+ {
55
+ "name": "Account",
56
+ "item": [
57
+ {
58
+ "name": "Create / Get Account",
59
+ "request": {
60
+ "method": "POST",
61
+ "header": [
62
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" },
63
+ { "key": "Content-Type", "value": "application/json" }
64
+ ],
65
+ "body": {
66
+ "mode": "raw",
67
+ "raw": "{\n \"displayName\": \"My Studio\",\n \"email\": \"dev@example.com\",\n \"commissionWallet\": \"{{playerWallet}}\"\n}"
68
+ },
69
+ "url": {
70
+ "raw": "{{baseUrl}}/api/developer/account",
71
+ "host": ["{{baseUrl}}"],
72
+ "path": ["api", "developer", "account"]
73
+ },
74
+ "description": "Create or retrieve developer account (upsert on wallet address). Called on first portal login."
75
+ }
76
+ },
77
+ {
78
+ "name": "Get Account",
79
+ "request": {
80
+ "method": "GET",
81
+ "header": [
82
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
83
+ ],
84
+ "url": {
85
+ "raw": "{{baseUrl}}/api/developer/account",
86
+ "host": ["{{baseUrl}}"],
87
+ "path": ["api", "developer", "account"]
88
+ },
89
+ "description": "Get current developer account details."
90
+ }
91
+ },
92
+ {
93
+ "name": "Update Account",
94
+ "request": {
95
+ "method": "PATCH",
96
+ "header": [
97
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" },
98
+ { "key": "Content-Type", "value": "application/json" }
99
+ ],
100
+ "body": {
101
+ "mode": "raw",
102
+ "raw": "{\n \"displayName\": \"Updated Name\",\n \"email\": \"new@example.com\",\n \"commissionWallet\": null\n}"
103
+ },
104
+ "url": {
105
+ "raw": "{{baseUrl}}/api/developer/account",
106
+ "host": ["{{baseUrl}}"],
107
+ "path": ["api", "developer", "account"]
108
+ },
109
+ "description": "Update developer account fields. All fields optional (COALESCE — null preserves existing)."
110
+ }
111
+ }
112
+ ]
113
+ },
114
+ {
115
+ "name": "Apps",
116
+ "item": [
117
+ {
118
+ "name": "Create App",
119
+ "request": {
120
+ "method": "POST",
121
+ "header": [
122
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" },
123
+ { "key": "Content-Type", "value": "application/json" }
124
+ ],
125
+ "body": {
126
+ "mode": "raw",
127
+ "raw": "{\n \"appName\": \"My Betting App\",\n \"description\": \"A sports betting app powered by Dubs\",\n \"websiteUrl\": \"https://myapp.com\"\n}"
128
+ },
129
+ "url": {
130
+ "raw": "{{baseUrl}}/api/developer/apps",
131
+ "host": ["{{baseUrl}}"],
132
+ "path": ["api", "developer", "apps"]
133
+ },
134
+ "description": "Create a new developer app. Returns the app record with its ID."
135
+ }
136
+ },
137
+ {
138
+ "name": "List Apps",
139
+ "request": {
140
+ "method": "GET",
141
+ "header": [
142
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
143
+ ],
144
+ "url": {
145
+ "raw": "{{baseUrl}}/api/developer/apps",
146
+ "host": ["{{baseUrl}}"],
147
+ "path": ["api", "developer", "apps"]
148
+ },
149
+ "description": "List all apps for the current developer (excludes soft-deleted)."
150
+ }
151
+ },
152
+ {
153
+ "name": "Get App",
154
+ "request": {
155
+ "method": "GET",
156
+ "header": [
157
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
158
+ ],
159
+ "url": {
160
+ "raw": "{{baseUrl}}/api/developer/apps/{{appId}}",
161
+ "host": ["{{baseUrl}}"],
162
+ "path": ["api", "developer", "apps", "{{appId}}"]
163
+ },
164
+ "description": "Get a single app with its API keys (hints only, never full keys)."
165
+ }
166
+ },
167
+ {
168
+ "name": "Update App",
169
+ "request": {
170
+ "method": "PATCH",
171
+ "header": [
172
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" },
173
+ { "key": "Content-Type", "value": "application/json" }
174
+ ],
175
+ "body": {
176
+ "mode": "raw",
177
+ "raw": "{\n \"appName\": \"Updated App Name\",\n \"description\": \"Updated description\",\n \"websiteUrl\": \"https://newsite.com\",\n \"networkMode\": \"open\"\n}"
178
+ },
179
+ "url": {
180
+ "raw": "{{baseUrl}}/api/developer/apps/{{appId}}",
181
+ "host": ["{{baseUrl}}"],
182
+ "path": ["api", "developer", "apps", "{{appId}}"]
183
+ },
184
+ "description": "Update app details. `networkMode` can be `\"open\"` or `\"private\"`. All fields optional."
185
+ }
186
+ },
187
+ {
188
+ "name": "Delete App",
189
+ "request": {
190
+ "method": "DELETE",
191
+ "header": [
192
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
193
+ ],
194
+ "url": {
195
+ "raw": "{{baseUrl}}/api/developer/apps/{{appId}}",
196
+ "host": ["{{baseUrl}}"],
197
+ "path": ["api", "developer", "apps", "{{appId}}"]
198
+ },
199
+ "description": "Soft-delete an app. Deactivates all API keys and sets status to 'deleted'."
200
+ }
201
+ }
202
+ ]
203
+ },
204
+ {
205
+ "name": "API Keys",
206
+ "item": [
207
+ {
208
+ "name": "Generate API Key",
209
+ "request": {
210
+ "method": "POST",
211
+ "header": [
212
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" },
213
+ { "key": "Content-Type", "value": "application/json" }
214
+ ],
215
+ "body": {
216
+ "mode": "raw",
217
+ "raw": "{\n \"environment\": \"sandbox\"\n}"
218
+ },
219
+ "url": {
220
+ "raw": "{{baseUrl}}/api/developer/apps/{{appId}}/keys",
221
+ "host": ["{{baseUrl}}"],
222
+ "path": ["api", "developer", "apps", "{{appId}}", "keys"]
223
+ },
224
+ "description": "Generate a new API key. Returns the full key **once** — save it immediately.\n\n`environment`: `\"sandbox\"` (prefix `dubs_test_`) or `\"production\"` (prefix `dubs_live_`)."
225
+ }
226
+ },
227
+ {
228
+ "name": "Revoke API Key",
229
+ "request": {
230
+ "method": "DELETE",
231
+ "header": [
232
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
233
+ ],
234
+ "url": {
235
+ "raw": "{{baseUrl}}/api/developer/keys/{{keyId}}",
236
+ "host": ["{{baseUrl}}"],
237
+ "path": ["api", "developer", "keys", "{{keyId}}"]
238
+ },
239
+ "description": "Revoke (deactivate) an API key."
240
+ }
241
+ }
242
+ ]
243
+ },
244
+ {
245
+ "name": "Analytics",
246
+ "item": [
247
+ {
248
+ "name": "Get Developer Stats",
249
+ "request": {
250
+ "method": "GET",
251
+ "header": [
252
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
253
+ ],
254
+ "url": {
255
+ "raw": "{{baseUrl}}/api/developer/stats",
256
+ "host": ["{{baseUrl}}"],
257
+ "path": ["api", "developer", "stats"]
258
+ },
259
+ "description": "Get aggregate developer stats: total games, total API calls, total apps."
260
+ }
261
+ },
262
+ {
263
+ "name": "Get App Usage",
264
+ "request": {
265
+ "method": "GET",
266
+ "header": [
267
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
268
+ ],
269
+ "url": {
270
+ "raw": "{{baseUrl}}/api/developer/apps/{{appId}}/usage",
271
+ "host": ["{{baseUrl}}"],
272
+ "path": ["api", "developer", "apps", "{{appId}}", "usage"]
273
+ },
274
+ "description": "Get API usage stats for an app (last 30 days). Daily call counts with avg response time."
275
+ }
276
+ }
277
+ ]
278
+ },
279
+ {
280
+ "name": "Webhooks",
281
+ "item": [
282
+ {
283
+ "name": "Create Webhook",
284
+ "request": {
285
+ "method": "POST",
286
+ "header": [
287
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" },
288
+ { "key": "Content-Type", "value": "application/json" }
289
+ ],
290
+ "body": {
291
+ "mode": "raw",
292
+ "raw": "{\n \"url\": \"https://myapp.com/webhooks/dubs\",\n \"events\": [\"game.created\", \"game.joined\"],\n \"description\": \"Main production webhook\"\n}"
293
+ },
294
+ "url": {
295
+ "raw": "{{baseUrl}}/api/developer/apps/{{appId}}/webhooks",
296
+ "host": ["{{baseUrl}}"],
297
+ "path": ["api", "developer", "apps", "{{appId}}", "webhooks"]
298
+ },
299
+ "description": "Register a new webhook. Returns signing secret **once** — save it.\n\nAllowed events: `game.created`, `game.joined`.\n\nURL must be HTTPS (localhost allowed for dev)."
300
+ }
301
+ },
302
+ {
303
+ "name": "List Webhooks",
304
+ "request": {
305
+ "method": "GET",
306
+ "header": [
307
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
308
+ ],
309
+ "url": {
310
+ "raw": "{{baseUrl}}/api/developer/apps/{{appId}}/webhooks",
311
+ "host": ["{{baseUrl}}"],
312
+ "path": ["api", "developer", "apps", "{{appId}}", "webhooks"]
313
+ },
314
+ "description": "List all webhooks for an app. Secret shown as hint only (`••••xxxx`)."
315
+ }
316
+ },
317
+ {
318
+ "name": "Update Webhook",
319
+ "request": {
320
+ "method": "PATCH",
321
+ "header": [
322
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" },
323
+ { "key": "Content-Type", "value": "application/json" }
324
+ ],
325
+ "body": {
326
+ "mode": "raw",
327
+ "raw": "{\n \"url\": \"https://myapp.com/webhooks/dubs-v2\",\n \"events\": [\"game.created\"],\n \"isActive\": true,\n \"description\": \"Updated webhook\"\n}"
328
+ },
329
+ "url": {
330
+ "raw": "{{baseUrl}}/api/developer/webhooks/{{webhookId}}",
331
+ "host": ["{{baseUrl}}"],
332
+ "path": ["api", "developer", "webhooks", "{{webhookId}}"]
333
+ },
334
+ "description": "Update webhook URL, events, active status, or description."
335
+ }
336
+ },
337
+ {
338
+ "name": "Delete Webhook",
339
+ "request": {
340
+ "method": "DELETE",
341
+ "header": [
342
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
343
+ ],
344
+ "url": {
345
+ "raw": "{{baseUrl}}/api/developer/webhooks/{{webhookId}}",
346
+ "host": ["{{baseUrl}}"],
347
+ "path": ["api", "developer", "webhooks", "{{webhookId}}"]
348
+ },
349
+ "description": "Delete a webhook and all its delivery logs."
350
+ }
351
+ },
352
+ {
353
+ "name": "Get Webhook Logs",
354
+ "request": {
355
+ "method": "GET",
356
+ "header": [
357
+ { "key": "Authorization", "value": "Bearer {{jwtToken}}" }
358
+ ],
359
+ "url": {
360
+ "raw": "{{baseUrl}}/api/developer/webhooks/{{webhookId}}/logs",
361
+ "host": ["{{baseUrl}}"],
362
+ "path": ["api", "developer", "webhooks", "{{webhookId}}", "logs"]
363
+ },
364
+ "description": "Recent delivery logs for a webhook (last 50). Shows status code, attempts, success/error."
365
+ }
366
+ }
367
+ ]
368
+ }
369
+ ]
370
+ },
371
+ {
372
+ "name": "Public API (API Key Auth)",
373
+ "description": "Third-party developer API. Requires `X-API-Key` header. Mounted at `/api/developer/v1`.",
374
+ "item": [
375
+ {
376
+ "name": "Events",
377
+ "description": "Browse upcoming bettable events from sports and esports.",
378
+ "item": [
379
+ {
380
+ "name": "Get Upcoming Events (Unified)",
381
+ "request": {
382
+ "method": "GET",
383
+ "header": [
384
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
385
+ ],
386
+ "url": {
387
+ "raw": "{{baseUrl}}/api/developer/v1/events/upcoming?type=sports&page=1&per_page=20",
388
+ "host": ["{{baseUrl}}"],
389
+ "path": ["api", "developer", "v1", "events", "upcoming"],
390
+ "query": [
391
+ { "key": "type", "value": "sports", "description": "\"sports\" or \"esports\". Omit for both." },
392
+ { "key": "game", "value": "", "description": "Filter: nba, nhl, mlb, nfl, epl, ufc, ncaab, ncaaf, cs-go, valorant", "disabled": true },
393
+ { "key": "page", "value": "1", "description": "Page number (default: 1)" },
394
+ { "key": "per_page", "value": "20", "description": "Items per page (default: 20, max: 100)" }
395
+ ]
396
+ },
397
+ "description": "Unified paginated endpoint for ALL upcoming bettable events (sports + esports).\n\nReturns `UnifiedEvent[]` with consistent shape across both types.\n\nFilters: `type` (sports/esports), `game` (specific league/videogame)."
398
+ }
399
+ },
400
+ {
401
+ "name": "Get Sports Events by League",
402
+ "request": {
403
+ "method": "GET",
404
+ "header": [
405
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
406
+ ],
407
+ "url": {
408
+ "raw": "{{baseUrl}}/api/developer/v1/sports/events/NBA",
409
+ "host": ["{{baseUrl}}"],
410
+ "path": ["api", "developer", "v1", "sports", "events", "NBA"]
411
+ },
412
+ "description": "Upcoming sports events for a single league.\n\nValid leagues: `NBA`, `NHL`, `MLB`, `NFL`, `EPL`, `UFC`, `NCAAF`, `NCAAB`."
413
+ }
414
+ },
415
+ {
416
+ "name": "Get Esports Matches",
417
+ "request": {
418
+ "method": "GET",
419
+ "header": [
420
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
421
+ ],
422
+ "url": {
423
+ "raw": "{{baseUrl}}/api/developer/v1/esports/matches/upcoming?videogame=cs-go",
424
+ "host": ["{{baseUrl}}"],
425
+ "path": ["api", "developer", "v1", "esports", "matches", "upcoming"],
426
+ "query": [
427
+ { "key": "videogame", "value": "cs-go", "description": "Filter: cs-go, valorant. Omit for all." }
428
+ ]
429
+ },
430
+ "description": "Upcoming esports matches (normalized UnifiedEvent shape).\n\nOptional `videogame` filter: `cs-go`, `valorant`."
431
+ }
432
+ },
433
+ {
434
+ "name": "Get Esports Match Detail",
435
+ "request": {
436
+ "method": "GET",
437
+ "header": [
438
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
439
+ ],
440
+ "url": {
441
+ "raw": "{{baseUrl}}/api/developer/v1/esports/matches/1353988",
442
+ "host": ["{{baseUrl}}"],
443
+ "path": ["api", "developer", "v1", "esports", "matches", "1353988"]
444
+ },
445
+ "description": "Detailed esports match info (EsportsMatchDetail shape — richer than unified).\n\nIncludes opponents, results, winnerId, serie, tournament, tier."
446
+ }
447
+ }
448
+ ]
449
+ },
450
+ {
451
+ "name": "Game Lifecycle",
452
+ "description": "Create, join, confirm, and claim bets.",
453
+ "item": [
454
+ {
455
+ "name": "Validate Event",
456
+ "request": {
457
+ "method": "POST",
458
+ "header": [
459
+ { "key": "X-API-Key", "value": "{{apiKey}}" },
460
+ { "key": "Content-Type", "value": "application/json" }
461
+ ],
462
+ "body": {
463
+ "mode": "raw",
464
+ "raw": "{\n \"id\": \"sports:NBA:espn-nba-401584793\"\n}"
465
+ },
466
+ "url": {
467
+ "raw": "{{baseUrl}}/api/developer/v1/games/validate",
468
+ "host": ["{{baseUrl}}"],
469
+ "path": ["api", "developer", "v1", "games", "validate"]
470
+ },
471
+ "description": "Check if an event is bettable. Lightweight yes/no.\n\nID format:\n- Sports: `sports:LEAGUE:EVENT_ID` (e.g. `sports:UFC:espn-ufc-600057329`)\n- Esports: `esports:MATCH_ID` (e.g. `esports:1353988`)\n\nReturns: `bettable`, `gameMode`, `lockTimestamp`, `startTime`, `status`."
472
+ }
473
+ },
474
+ {
475
+ "name": "Create Game",
476
+ "request": {
477
+ "method": "POST",
478
+ "header": [
479
+ { "key": "X-API-Key", "value": "{{apiKey}}" },
480
+ { "key": "Content-Type", "value": "application/json" }
481
+ ],
482
+ "body": {
483
+ "mode": "raw",
484
+ "raw": "{\n \"id\": \"sports:NBA:espn-nba-401584793\",\n \"playerWallet\": \"{{playerWallet}}\",\n \"teamChoice\": \"home\",\n \"wagerAmount\": 0.1\n}"
485
+ },
486
+ "url": {
487
+ "raw": "{{baseUrl}}/api/developer/v1/games/create",
488
+ "host": ["{{baseUrl}}"],
489
+ "path": ["api", "developer", "v1", "games", "create"]
490
+ },
491
+ "description": "Resolve event, validate, and build an unsigned create+join transaction.\n\nThe `transaction` field is a base64-encoded unsigned Solana Transaction. Have the user sign it with their wallet, then send the signature to `/games/confirm`.\n\n`teamChoice`: `home`, `away`, or `draw`.\n`wagerAmount`: SOL amount."
492
+ }
493
+ },
494
+ {
495
+ "name": "Join Game",
496
+ "request": {
497
+ "method": "POST",
498
+ "header": [
499
+ { "key": "X-API-Key", "value": "{{apiKey}}" },
500
+ { "key": "Content-Type", "value": "application/json" }
501
+ ],
502
+ "body": {
503
+ "mode": "raw",
504
+ "raw": "{\n \"playerWallet\": \"{{playerWallet}}\",\n \"gameId\": \"{{gameId}}\",\n \"teamChoice\": \"away\",\n \"amount\": 0.1\n}"
505
+ },
506
+ "url": {
507
+ "raw": "{{baseUrl}}/api/developer/v1/games/join",
508
+ "host": ["{{baseUrl}}"],
509
+ "path": ["api", "developer", "v1", "games", "join"]
510
+ },
511
+ "description": "Build an unsigned join transaction for an existing game.\n\nIncludes network mode visibility check — private apps can only join their own games.\n\nSign the returned `transaction` and confirm via `/games/confirm`."
512
+ }
513
+ },
514
+ {
515
+ "name": "Confirm Game",
516
+ "request": {
517
+ "method": "POST",
518
+ "header": [
519
+ { "key": "X-API-Key", "value": "{{apiKey}}" },
520
+ { "key": "Content-Type", "value": "application/json" }
521
+ ],
522
+ "body": {
523
+ "mode": "raw",
524
+ "raw": "{\n \"gameId\": \"{{gameId}}\",\n \"playerWallet\": \"{{playerWallet}}\",\n \"signature\": \"SOLANA_TX_SIGNATURE\",\n \"teamChoice\": \"home\",\n \"wagerAmount\": 0.1,\n \"role\": \"creator\",\n \"gameAddress\": \"GAME_PDA_ADDRESS\"\n}"
525
+ },
526
+ "url": {
527
+ "raw": "{{baseUrl}}/api/developer/v1/games/confirm",
528
+ "host": ["{{baseUrl}}"],
529
+ "path": ["api", "developer", "v1", "games", "confirm"]
530
+ },
531
+ "description": "Confirm a signed transaction and persist the game to DB.\n\n`role`: `\"creator\"` (after /create) or `\"joiner\"` (after /join).\n\nFor creators, retrieves stashed event data server-side (from /create step). Stash expires after 10 minutes.\n\nCreates developer attribution record. Fires webhooks (`game.created` or `game.joined`)."
532
+ }
533
+ },
534
+ {
535
+ "name": "Build Claim Transaction",
536
+ "request": {
537
+ "method": "POST",
538
+ "header": [
539
+ { "key": "X-API-Key", "value": "{{apiKey}}" },
540
+ { "key": "Content-Type", "value": "application/json" }
541
+ ],
542
+ "body": {
543
+ "mode": "raw",
544
+ "raw": "{\n \"playerWallet\": \"{{playerWallet}}\",\n \"gameId\": \"{{gameId}}\"\n}"
545
+ },
546
+ "url": {
547
+ "raw": "{{baseUrl}}/api/developer/v1/transactions/build/claim",
548
+ "host": ["{{baseUrl}}"],
549
+ "path": ["api", "developer", "v1", "transactions", "build", "claim"]
550
+ },
551
+ "description": "Build an unsigned claim transaction for a resolved game.\n\nHave the user sign the returned `transaction` to claim their winnings."
552
+ }
553
+ }
554
+ ]
555
+ },
556
+ {
557
+ "name": "Games",
558
+ "description": "Query existing games.",
559
+ "item": [
560
+ {
561
+ "name": "Get Game Detail",
562
+ "request": {
563
+ "method": "GET",
564
+ "header": [
565
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
566
+ ],
567
+ "url": {
568
+ "raw": "{{baseUrl}}/api/developer/v1/games/{{gameId}}",
569
+ "host": ["{{baseUrl}}"],
570
+ "path": ["api", "developer", "v1", "games", "{{gameId}}"]
571
+ },
572
+ "description": "Get full game detail: players, pools, status, sportsEvent, media."
573
+ }
574
+ },
575
+ {
576
+ "name": "List Games",
577
+ "request": {
578
+ "method": "GET",
579
+ "header": [
580
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
581
+ ],
582
+ "url": {
583
+ "raw": "{{baseUrl}}/api/developer/v1/games?status=open&limit=20&offset=0",
584
+ "host": ["{{baseUrl}}"],
585
+ "path": ["api", "developer", "v1", "games"],
586
+ "query": [
587
+ { "key": "wallet", "value": "", "description": "Filter by player wallet address", "disabled": true },
588
+ { "key": "status", "value": "open", "description": "open | locked | resolved" },
589
+ { "key": "limit", "value": "20", "description": "Max results (default: 20)" },
590
+ { "key": "offset", "value": "0", "description": "Pagination offset (default: 0)" }
591
+ ]
592
+ },
593
+ "description": "List games visible to your app.\n\n- **Private apps**: Only see games created through your app.\n- **Open apps**: See games from other open apps + unattributed (main Dubs) + own games.\n\n`status=open` excludes games past their lock time."
594
+ }
595
+ },
596
+ {
597
+ "name": "List Network Games",
598
+ "request": {
599
+ "method": "GET",
600
+ "header": [
601
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
602
+ ],
603
+ "url": {
604
+ "raw": "{{baseUrl}}/api/developer/v1/network/games?limit=20&offset=0",
605
+ "host": ["{{baseUrl}}"],
606
+ "path": ["api", "developer", "v1", "network", "games"],
607
+ "query": [
608
+ { "key": "league", "value": "", "description": "Filter: NBA, NHL, MLB, NFL, EPL, UFC, NCAAB, NCAAF", "disabled": true },
609
+ { "key": "limit", "value": "20", "description": "Max results (default: 20)" },
610
+ { "key": "offset", "value": "0", "description": "Pagination offset (default: 0)" }
611
+ ]
612
+ },
613
+ "description": "Fetch joinable open games from the Dubs network.\n\n**Requires open network mode** — returns 403 for private apps.\n\nFilters: sports games only (game_mode=4), pending, not locked, not resolved, lock time in future.\n\nOptional `league` filter maps abbreviations to DB values (e.g. EPL → English Premier League).\n\nIncludes pagination with total count."
614
+ }
615
+ }
616
+ ]
617
+ },
618
+ {
619
+ "name": "Errors",
620
+ "description": "Solana program error parsing utilities.",
621
+ "item": [
622
+ {
623
+ "name": "Parse Solana Error",
624
+ "request": {
625
+ "method": "POST",
626
+ "header": [
627
+ { "key": "X-API-Key", "value": "{{apiKey}}" },
628
+ { "key": "Content-Type", "value": "application/json" }
629
+ ],
630
+ "body": {
631
+ "mode": "raw",
632
+ "raw": "{\n \"error\": {\n \"InstructionError\": [0, { \"Custom\": 6004 }]\n }\n}"
633
+ },
634
+ "url": {
635
+ "raw": "{{baseUrl}}/api/developer/v1/errors/parse",
636
+ "host": ["{{baseUrl}}"],
637
+ "path": ["api", "developer", "v1", "errors", "parse"]
638
+ },
639
+ "description": "Decode a raw Solana transaction error into a human-readable `{ code, message }`.\n\nHandles custom program errors (6000-6049), built-in instruction errors, and string errors."
640
+ }
641
+ },
642
+ {
643
+ "name": "Get Error Codes",
644
+ "request": {
645
+ "method": "GET",
646
+ "header": [
647
+ { "key": "X-API-Key", "value": "{{apiKey}}" }
648
+ ],
649
+ "url": {
650
+ "raw": "{{baseUrl}}/api/developer/v1/errors/codes",
651
+ "host": ["{{baseUrl}}"],
652
+ "path": ["api", "developer", "v1", "errors", "codes"]
653
+ },
654
+ "description": "Return the full map of Solana program error codes (6000-6049) for client-side use.\n\nUseful for building local error parsers without API calls."
655
+ }
656
+ }
657
+ ]
658
+ }
659
+ ]
660
+ }
661
+ ]
662
+ }