{
  "openapi": "3.1.0",
  "info": {
    "title": "LoyaltyVIP API",
    "version": "1.1.0",
    "summary": "A player's casino loyalty data and features, plus the full public casino directory.",
    "description": "Programmatic access for developers and AI agents.\n\n- **Public** (no key): the casino directory — casinos, casino detail with rewards program + tier ladder, and rewards programs.\n- **Account** (API key): the key owner's tiers, trips, offers, and profile.\n- **Full action API**: `POST /v1/player` exposes the complete ~70-action player & host surface (trips, sessions, bankroll, offers, tiers, visits, vouchers, machines, W-2G/tax, optimizers, sharing, consent, social, notifications, host dashboard/leads). Plus standalone feature endpoints (comps, tier-match, predictions, responsible gaming, host discovery, tax reports).\n\nAuthenticate with a personal API key as a Bearer token. Keys carry umbrella scopes: `read`, `write`, `tax`, `host`. Admin actions and API-key management are never available via API key. Create/manage keys at https://loyaltyvip.com/dashboard/developer.\n\n## Conventions\n\n- **Errors** are JSON `{ \"error\": { code, message, status, docs } }`. Canonical codes: `invalid_token` (401), `insufficient_scope` (403), `not_found` (404), `rate_limited` (429), `internal_error` (500). A 401 also returns a `WWW-Authenticate` header with a `resource_metadata` pointer.\n- **Rate limits**: responses carry `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. On 429, honor `Retry-After`. Retry 5xx with exponential backoff (~1s, 2s, 4s; max 3 tries).\n- **Idempotency**: send an `Idempotency-Key` header (a UUID) on write requests so retries are safe; the same key replays the original result.\n- **Pagination**: list endpoints use `limit` + `offset` and return `count`. Cursor pagination is planned.\n- **Versioning & deprecation**: the API is versioned in the path (`/v1`). Breaking changes ship under a new version; deprecations are announced with `Deprecation` and `Sunset` response headers and on https://loyaltyvip.com/developers.\n- **Streaming**: the NLWeb endpoint (`POST https://loyaltyvip.com/ask`) and the MCP server (`https://loyaltyvip.com/mcp`) support Server-Sent Events for incremental results.",
    "contact": { "name": "LoyaltyVIP Developers", "email": "support@loyaltyvip.com", "url": "https://loyaltyvip.com/developers" },
    "termsOfService": "https://loyaltyvip.com/terms",
    "license": { "name": "Proprietary", "url": "https://loyaltyvip.com/terms" }
  },
  "externalDocs": { "description": "Full agent & developer reference", "url": "https://loyaltyvip.com/llms-full.txt" },
  "servers": [{ "url": "https://nbhagdwegk.execute-api.us-east-1.amazonaws.com", "description": "Production API base" }],
  "security": [{ "ApiKeyAuth": [] }],
  "tags": [
    { "name": "Directory", "description": "Public casino directory (no key)." },
    { "name": "Account", "description": "The key owner's account (scope: read)." },
    { "name": "Player API", "description": "Full player & host action surface via POST /v1/player." },
    { "name": "Features", "description": "Comps, tier-match, predictions, responsible gaming, host discovery, tax." }
  ],
  "paths": {
    "/v1/casinos": {
      "get": {
        "tags": ["Directory"], "operationId": "listCasinos", "summary": "Search casinos", "description": "Search the public U.S. casino directory by name, state, type, or rewards availability. Offset/limit pagination; returns a total count.", "security": [],
        "parameters": [
          { "name": "q", "in": "query", "schema": { "type": "string" }, "description": "Name search." },
          { "name": "state", "in": "query", "schema": { "type": "string" }, "description": "Two-letter state code." },
          { "name": "type", "in": "query", "schema": { "type": "string" }, "description": "casino_type (commercial|tribal|racino…)." },
          { "name": "has_rewards", "in": "query", "schema": { "type": "boolean" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 24, "maximum": 100 } },
          { "name": "offset", "in": "query", "schema": { "type": "integer", "default": 0 } }
        ],
        "responses": {
          "200": { "description": "Casinos", "headers": { "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" } }, "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Casino" } }, "count": { "type": "integer" } } } } } },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/casinos/{slug}": {
      "get": {
        "tags": ["Directory"], "operationId": "getCasino", "summary": "Casino detail + rewards program + tier ladder", "description": "Full detail for one casino including its rewards/players-club program and tier ladder.", "security": [],
        "parameters": [{ "name": "slug", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Casino detail", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "allOf": [{ "$ref": "#/components/schemas/Casino" }, { "type": "object", "properties": { "rewards_program": { "$ref": "#/components/schemas/RewardsProgram" }, "tiers": { "type": "array", "items": { "$ref": "#/components/schemas/Tier" } } } }] } } } } } },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/rewards-programs": {
      "get": {
        "tags": ["Directory"], "operationId": "listRewardsPrograms", "summary": "List rewards programs", "description": "List casino rewards/players-club programs, optionally filtered by search term or brand.", "security": [],
        "parameters": [
          { "name": "search", "in": "query", "schema": { "type": "string" } },
          { "name": "brand", "in": "query", "schema": { "type": "string" } },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 100, "maximum": 200 } }
        ],
        "responses": {
          "200": { "description": "Programs", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/RewardsProgram" } }, "count": { "type": "integer" } } } } } },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/rewards-programs/{id}": {
      "get": {
        "tags": ["Directory"], "operationId": "getRewardsProgram", "summary": "Rewards program + tier ladder", "description": "One rewards program with its full tier ladder.", "security": [],
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" } }],
        "responses": {
          "200": { "description": "Program + tiers", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "allOf": [{ "$ref": "#/components/schemas/RewardsProgram" }, { "type": "object", "properties": { "tiers": { "type": "array", "items": { "$ref": "#/components/schemas/Tier" } } } }] } } } } } },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/TooManyRequests" },
          "500": { "$ref": "#/components/responses/ServerError" }
        }
      }
    },
    "/v1/me": { "get": { "tags": ["Account"], "operationId": "getMe", "summary": "The key owner", "description": "Profile of the account that owns the API key.", "responses": { "200": { "description": "Account", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "$ref": "#/components/schemas/Account" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/tiers": { "get": { "tags": ["Account"], "operationId": "listTiers", "summary": "Your casino tiers", "description": "The key owner's tier status and points at each casino.", "responses": { "200": { "description": "Tiers", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/UserTier" } }, "count": { "type": "integer" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/trips": { "get": { "tags": ["Account"], "operationId": "listTrips", "summary": "Your trips", "description": "The key owner's trips.", "responses": { "200": { "description": "Trips", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Trip" } }, "count": { "type": "integer" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/offers": { "get": { "tags": ["Account"], "operationId": "listOffers", "summary": "Your offers", "description": "The key owner's casino offers.", "responses": { "200": { "description": "Offers", "content": { "application/json": { "schema": { "type": "object", "properties": { "data": { "type": "array", "items": { "$ref": "#/components/schemas/Offer" } }, "count": { "type": "integer" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/player": {
      "post": {
        "tags": ["Player API"], "operationId": "playerAction",
        "summary": "Full player & host action API",
        "description": "Invoke any of ~70 player/host actions by name. Reads need scope `read`, writes `write`, tax actions `tax`, host actions `host`. Examples: list_trips, get_trip, tier_status, bankroll_status, list_w2g, tax_year_summary, freeplay_optimizer, card_recommendation, tier_retention_plan, list_share_links, list_notifications, add_trip, upsert_tier, bankroll_add, create_share_link, manual_w2g, host_dashboard. Admin + key-management actions are rejected (403). For write actions, send an `Idempotency-Key` header so retries are safe.",
        "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["action"], "properties": { "action": { "type": "string", "example": "tax_year_summary" } }, "additionalProperties": true } } } },
        "responses": { "200": { "description": "Action result (shape depends on the action; always { data: { success, ... } }).", "content": { "application/json": { "schema": { "type": "object" } } } }, "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } }
      }
    },
    "/v1/comp/calculate": { "post": { "tags": ["Features"], "operationId": "compCalculate", "summary": "Comp calculator", "description": "actions: calculate | analyze_history | get_comp_ratios. Scope: read.", "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }], "requestBody": { "$ref": "#/components/requestBodies/Action" }, "responses": { "200": { "description": "Result", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/comp/predict": { "post": { "tags": ["Features"], "operationId": "compPredict", "summary": "Comp / offer prediction", "description": "actions: predict | predict_all_casinos. Scope: read.", "requestBody": { "$ref": "#/components/requestBodies/Action" }, "responses": { "200": { "description": "Result", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/tier-match": { "post": { "tags": ["Features"], "operationId": "tierMatch", "summary": "Tier match suggestions + letters", "description": "actions: get_suggestions | generate_letter | create_request | get_requests | get_templates. Scope: read (writes via write).", "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }], "requestBody": { "$ref": "#/components/requestBodies/Action" }, "responses": { "200": { "description": "Result", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/rg": { "post": { "tags": ["Features"], "operationId": "responsibleGaming", "summary": "Responsible gaming profile + limits", "description": "actions: get_risk_profile | get_resources | set_budget | set_session_limit. Scope: read.", "requestBody": { "$ref": "#/components/requestBodies/Action" }, "responses": { "200": { "description": "Result", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/hosts/discover": { "post": { "tags": ["Features"], "operationId": "discoverHosts", "summary": "Discover / connect with hosts", "description": "actions: search_hosts | get_host_profile | get_featured_hosts | get_my_connections | request_connection. Scope: read.", "requestBody": { "$ref": "#/components/requestBodies/Action" }, "responses": { "200": { "description": "Result", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/match-hosts": { "post": { "tags": ["Features"], "operationId": "matchHosts", "summary": "Best-host matches for the caller", "description": "Body: { player_id (must be your own user id), limit }. Scope: read.", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "player_id": { "type": "string" }, "limit": { "type": "integer", "default": 5 } } } } } }, "responses": { "200": { "description": "Matches", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } },
    "/v1/tax-report": { "post": { "tags": ["Features"], "operationId": "taxReport", "summary": "IRS gambling tax docs", "description": "actions: generate_summary | generate_session_log | generate_w2g_report. Optional tax_year. Scope: tax.", "parameters": [{ "$ref": "#/components/parameters/IdempotencyKey" }], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["action"], "properties": { "action": { "type": "string" }, "tax_year": { "type": "integer" } } } } } }, "responses": { "200": { "description": "Report", "content": { "application/json": { "schema": { "type": "object" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "429": { "$ref": "#/components/responses/TooManyRequests" }, "500": { "$ref": "#/components/responses/ServerError" } } } }
  },
  "components": {
    "securitySchemes": { "ApiKeyAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "lvip_live_*", "description": "Personal API key as a Bearer token. Scopes: read, write, tax, host. Create at https://loyaltyvip.com/dashboard/developer." } },
    "parameters": {
      "IdempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": false, "schema": { "type": "string", "format": "uuid" }, "description": "Optional UUID for safe retries of write requests. Replaying the same key returns the original result." }
    },
    "headers": {
      "RateLimitLimit": { "description": "Request quota for the current window.", "schema": { "type": "integer" } },
      "RateLimitRemaining": { "description": "Requests remaining in the current window.", "schema": { "type": "integer" } },
      "RateLimitReset": { "description": "Unix epoch seconds when the window resets.", "schema": { "type": "integer" } },
      "RetryAfter": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } },
      "Deprecation": { "description": "Set when the endpoint is deprecated (RFC 8594).", "schema": { "type": "string" } },
      "Sunset": { "description": "HTTP date after which a deprecated endpoint is removed (RFC 8594).", "schema": { "type": "string" } }
    },
    "requestBodies": { "Action": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["action"], "properties": { "action": { "type": "string" } }, "additionalProperties": true } } } } },
    "responses": {
      "BadRequest": { "description": "Malformed request (e.g. missing or unknown action).", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Unauthorized": { "description": "Missing or invalid API key.", "headers": { "WWW-Authenticate": { "schema": { "type": "string" }, "description": "Bearer challenge with a resource_metadata pointer." } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": { "code": "invalid_token", "message": "Missing or invalid API key.", "status": 401, "docs": "https://loyaltyvip.com/developers" } } } } },
      "Forbidden": { "description": "Key missing the required scope (read/write/tax/host), or action not allowed via API key.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": { "code": "insufficient_scope", "message": "This key lacks the required scope.", "status": 403, "docs": "https://loyaltyvip.com/developers" } } } } },
      "NotFound": { "description": "Not found.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "TooManyRequests": { "description": "Rate limit exceeded. Honor Retry-After.", "headers": { "Retry-After": { "$ref": "#/components/headers/RetryAfter" }, "X-RateLimit-Limit": { "$ref": "#/components/headers/RateLimitLimit" }, "X-RateLimit-Remaining": { "$ref": "#/components/headers/RateLimitRemaining" }, "X-RateLimit-Reset": { "$ref": "#/components/headers/RateLimitReset" } }, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": { "code": "rate_limited", "message": "Too many requests. Retry after the indicated delay.", "status": 429, "docs": "https://loyaltyvip.com/developers" } } } } },
      "ServerError": { "description": "Unexpected server error. Retry with exponential backoff.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": { "code": "internal_error", "message": "Something went wrong on our end.", "status": 500, "docs": "https://loyaltyvip.com/developers" } } } } }
    },
    "schemas": {
      "Casino": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "slug": { "type": "string" }, "name_slug": { "type": ["string", "null"] }, "state_slug": { "type": ["string", "null"] }, "name": { "type": "string" }, "city": { "type": ["string", "null"] }, "state": { "type": ["string", "null"] }, "county": { "type": ["string", "null"] }, "country": { "type": ["string", "null"] }, "lat": { "type": ["number", "null"] }, "lon": { "type": ["number", "null"] }, "casino_type": { "type": ["string", "null"] }, "tribal_nation": { "type": ["string", "null"] }, "nigc_license_type": { "type": ["string", "null"] }, "opened_year": { "type": ["integer", "null"] }, "gaming_floor_sqft": { "type": ["integer", "null"] }, "slot_machines": { "type": ["integer", "null"] }, "table_games": { "type": ["integer", "null"] }, "website": { "type": ["string", "null"] }, "brand": { "type": ["string", "null"] }, "has_hotel": { "type": ["boolean", "null"] }, "hotel_rooms": { "type": ["integer", "null"] }, "has_rewards_program": { "type": "boolean" } } },
      "RewardsProgram": { "type": "object", "properties": { "id": { "type": "string", "format": "uuid" }, "program_name": { "type": "string" }, "brand": { "type": ["string", "null"] }, "property": { "type": ["string", "null"] }, "region": { "type": ["string", "null"] }, "url": { "type": ["string", "null"] } } },
      "Tier": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "level": { "type": "integer" }, "qualification": { "type": ["string", "null"] }, "qualification_amount": { "type": ["number", "null"] }, "qualification_unit": { "type": ["string", "null"] }, "benefits": { "type": "array", "items": {} }, "verified": { "type": "boolean" } } },
      "Account": { "type": "object", "properties": { "id": { "type": "string" }, "email": { "type": "string" }, "name": { "type": ["string", "null"] }, "role": { "type": "string" } } },
      "UserTier": { "type": "object", "properties": { "id": { "type": "string" }, "casino_name": { "type": "string" }, "tier": { "type": "string" }, "points_balance": { "type": "number" }, "points_needed": { "type": "number" }, "tier_expires_at": { "type": ["string", "null"] }, "ytd_coin_in": { "type": "number" }, "ytd_theo": { "type": "number" } } },
      "Trip": { "type": "object", "properties": { "id": { "type": "string" }, "casino_name": { "type": "string" }, "property": { "type": ["string", "null"] }, "start_date": { "type": ["string", "null"] }, "end_date": { "type": ["string", "null"] }, "coin_in": { "type": ["number", "null"] }, "created_at": { "type": "string" } } },
      "Offer": { "type": "object", "properties": { "id": { "type": "string" }, "casino_name": { "type": "string" }, "offer_type": { "type": ["string", "null"] }, "value": { "type": ["number", "null"] }, "status": { "type": ["string", "null"] }, "expiration_date": { "type": ["string", "null"] }, "created_at": { "type": "string" } } },
      "Error": { "type": "object", "required": ["error"], "properties": { "error": { "type": "object", "required": ["code", "message", "status"], "properties": { "code": { "type": "string", "description": "Stable machine code: invalid_token | insufficient_scope | not_found | rate_limited | internal_error." }, "message": { "type": "string" }, "status": { "type": "integer" }, "docs": { "type": "string" } } } } }
    }
  }
}
