openapi: 3.1.0 info: title: Hermes API version: 0.1.0 description: Native betting study prototype API. servers: - url: http://localhost:3000 paths: /health: get: summary: Health check responses: '200': description: Service health content: application/json: schema: $ref: '#/components/schemas/HealthResponse' /api/v1/session/start: post: summary: Start a session requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/SessionStartRequest' responses: '201': description: Session started content: application/json: schema: $ref: '#/components/schemas/SessionResponse' /api/v1/session/end: post: summary: End the current session responses: '200': description: Session ended content: application/json: schema: $ref: '#/components/schemas/SessionResponse' /api/v1/session/me: get: summary: Inspect the current session responses: '200': description: Current session snapshot content: application/json: schema: $ref: '#/components/schemas/SessionResponse' /api/v1/feed/next: get: summary: Fetch the next round responses: '200': description: Next event payload content: application/json: schema: $ref: '#/components/schemas/Event' /api/v1/events/{event_id}: get: summary: Fetch an event parameters: - name: event_id in: path required: true schema: type: string format: uuid responses: '200': description: Event content: application/json: schema: $ref: '#/components/schemas/Event' /api/v1/events/{event_id}/manifest: get: summary: Fetch the event manifest parameters: - name: event_id in: path required: true schema: type: string format: uuid responses: '200': description: Manifest content: application/json: schema: $ref: '#/components/schemas/EventManifest' /api/v1/events/{event_id}/markets: get: summary: List markets for an event parameters: - name: event_id in: path required: true schema: type: string format: uuid responses: '200': description: Markets content: application/json: schema: type: array items: $ref: '#/components/schemas/Market' /api/v1/markets/{market_id}/odds/current: get: summary: Fetch current odds for a market parameters: - name: market_id in: path required: true schema: type: string format: uuid responses: '200': description: Current odds content: application/json: schema: $ref: '#/components/schemas/OddsVersion' /api/v1/stream: get: summary: Live odds and state stream responses: '200': description: Server-sent events stream content: text/event-stream: schema: type: string /api/v1/bets/intent: post: summary: Submit a bet intent requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/BetIntentRequest' responses: '201': description: Bet intent result content: application/json: schema: $ref: '#/components/schemas/BetIntentResponse' /api/v1/bets/{bet_intent_id}: get: summary: Fetch a bet intent parameters: - name: bet_intent_id in: path required: true schema: type: string format: uuid responses: '200': description: Bet intent content: application/json: schema: $ref: '#/components/schemas/BetIntentResponse' /api/v1/events/{event_id}/result: get: summary: Fetch event result parameters: - name: event_id in: path required: true schema: type: string format: uuid responses: '200': description: Result payload content: application/json: schema: $ref: '#/components/schemas/Settlement' /api/v1/analytics/batch: post: summary: Ingest analytics batch requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AnalyticsBatchRequest' responses: '202': description: Accepted /api/v1/experiments/config: get: summary: Fetch experiment config responses: '200': description: Experiment config content: application/json: schema: $ref: '#/components/schemas/ExperimentConfig' /api/v1/localization/{locale_code}: get: summary: Fetch a localization bundle parameters: - name: locale_code in: path required: true schema: type: string enum: [en, sv] responses: '200': description: Localization bundle content: application/json: schema: $ref: '#/components/schemas/LocalizationBundle' /api/v1/admin/events: post: summary: Create an event responses: '201': description: Created /api/v1/admin/markets: post: summary: Create a market responses: '201': description: Created /api/v1/admin/odds: post: summary: Publish odds responses: '201': description: Created /api/v1/admin/settlements: post: summary: Publish a settlement responses: '201': description: Created components: schemas: HealthResponse: type: object required: [status, service_name, environment, version, uptime_ms, database_ready, redis_ready] properties: status: type: string service_name: type: string environment: type: string version: type: string uptime_ms: type: integer database_ready: type: boolean redis_ready: type: boolean SessionStartRequest: type: object properties: external_ref: type: string locale_code: type: string device_platform: type: string device_model: type: string os_version: type: string app_version: type: string SessionResponse: type: object required: [session_id, user_id, started_at, experiment_variant, app_version, locale_code, device_platform] properties: session_id: type: string format: uuid user_id: type: string format: uuid started_at: type: string format: date-time ended_at: type: string format: date-time nullable: true experiment_variant: type: string app_version: type: string device_model: type: string nullable: true os_version: type: string nullable: true locale_code: type: string device_platform: type: string Event: type: object required: [id, sport_type, source_ref, title_en, title_sv, status, lock_at, settle_at] properties: id: type: string format: uuid sport_type: type: string source_ref: type: string title_en: type: string title_sv: type: string status: type: string preview_start_ms: type: integer preview_end_ms: type: integer reveal_start_ms: type: integer reveal_end_ms: type: integer lock_at: type: string format: date-time settle_at: type: string format: date-time EventManifest: type: object properties: event: $ref: '#/components/schemas/Event' media: type: array items: $ref: '#/components/schemas/EventMedia' markets: type: array items: $ref: '#/components/schemas/Market' EventMedia: type: object required: [id, event_id, media_type, hls_master_url, duration_ms] properties: id: type: string format: uuid event_id: type: string format: uuid media_type: type: string hls_master_url: type: string poster_url: type: string nullable: true duration_ms: type: integer preview_start_ms: type: integer preview_end_ms: type: integer reveal_start_ms: type: integer reveal_end_ms: type: integer Market: type: object required: [id, event_id, question_key, market_type, status, lock_at, settlement_rule_key] properties: id: type: string format: uuid event_id: type: string format: uuid question_key: type: string market_type: type: string status: type: string lock_at: type: string format: date-time settlement_rule_key: type: string outcomes: type: array items: $ref: '#/components/schemas/Outcome' Outcome: type: object required: [id, market_id, outcome_code, label_key, sort_order] properties: id: type: string format: uuid market_id: type: string format: uuid outcome_code: type: string label_key: type: string sort_order: type: integer OddsVersion: type: object required: [id, market_id, version_no, created_at, is_current] properties: id: type: string format: uuid market_id: type: string format: uuid version_no: type: integer created_at: type: string format: date-time is_current: type: boolean odds: type: array items: $ref: '#/components/schemas/OutcomeOdds' OutcomeOdds: type: object required: [id, odds_version_id, outcome_id, decimal_odds, fractional_num, fractional_den] properties: id: type: string format: uuid odds_version_id: type: string format: uuid outcome_id: type: string format: uuid decimal_odds: type: number fractional_num: type: integer fractional_den: type: integer BetIntentRequest: type: object required: [session_id, event_id, market_id, outcome_id, idempotency_key, client_sent_at] properties: session_id: type: string format: uuid event_id: type: string format: uuid market_id: type: string format: uuid outcome_id: type: string format: uuid idempotency_key: type: string client_sent_at: type: string format: date-time BetIntentResponse: type: object required: [id, accepted, acceptance_code, server_received_at] properties: id: type: string format: uuid accepted: type: boolean acceptance_code: type: string accepted_odds_version_id: type: string format: uuid nullable: true server_received_at: type: string format: date-time Settlement: type: object required: [id, market_id, settled_at, winning_outcome_id] properties: id: type: string format: uuid market_id: type: string format: uuid settled_at: type: string format: date-time winning_outcome_id: type: string format: uuid AnalyticsBatchRequest: type: object required: [events] properties: events: type: array items: $ref: '#/components/schemas/AnalyticsEventInput' AnalyticsEventInput: type: object required: [event_name, occurred_at] properties: event_name: type: string occurred_at: type: string format: date-time attributes: type: array items: $ref: '#/components/schemas/AttributeInput' AttributeInput: type: object required: [key, value] properties: key: type: string value: type: string ExperimentConfig: type: object properties: variant: type: string feature_flags: type: object additionalProperties: type: boolean LocalizationBundle: type: object required: [locale_code, values] properties: locale_code: type: string values: type: object additionalProperties: type: string ErrorResponse: type: object required: [code, message] properties: code: type: string message: type: string