{
  "openapi": "3.1.0",
  "info": {
    "title": "CashbackAll API",
    "description": "Public read-only API for cashback rate comparison across 19+ portals and 1000+ stores. SEO P3.3 (2026-05-13): added per-endpoint examples + rate-limit headers + the /api/stores/{slug} response schema for AI agent introspection. Original 20h marathon iter 65 (2026-05-05).",
    "version": "1.1.0",
    "license": { "name": "Proprietary" },
    "contact": { "url": "https://cashbackall.com/.well-known/security.txt" }
  },
  "servers": [
    { "url": "https://cashbackall.com", "description": "Production" }
  ],
  "x-rate-limit": {
    "description": "60 requests/minute per IP for unauthenticated calls. Responses carry standard X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Exceeding the limit returns HTTP 429 with a Retry-After header (seconds until reset)."
  },
  "x-llm-quickstart": {
    "description": "For LLM agents: see /llms.txt for a task-oriented quickstart. The most common pattern is: GET /api/stores/{slug} for one store's full rate breakdown, sorted high-to-low.",
    "preferredEndpoints": [
      "/api/stores/{slug}",
      "/api/deals",
      "/api/portals"
    ]
  },
  "paths": {
    "/api/health": {
      "get": {
        "summary": "Health check",
        "description": "Uptime + Supabase connectivity probe. Used by load balancers and Docker healthcheck.",
        "responses": {
          "200": {
            "description": "OK — healthy",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "uptimeSeconds": { "type": "number" },
                    "checks": { "type": "object" }
                  }
                },
                "example": {
                  "status": "ok",
                  "uptimeSeconds": 84321,
                  "checks": { "supabase": "ok", "memory": "ok" }
                }
              }
            }
          },
          "503": { "description": "Unhealthy — DB unreachable" }
        }
      }
    },
    "/api/portals": {
      "get": {
        "summary": "List active cashback portals",
        "description": "Returns metadata for all 19+ cashback portals (Rakuten, TopCashback, BeFrugal, etc.). Cached for 60s server-side + 1h client/CDN.",
        "responses": {
          "200": {
            "description": "Portals",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array",
                  "items": { "$ref": "#/components/schemas/Portal" }
                },
                "example": [
                  {
                    "id": "12345678-1234-1234-1234-123456789012",
                    "slug": "rakuten",
                    "name": "Rakuten",
                    "logo_url": "https://cashbackall.com/logos/rakuten.png",
                    "website_url": "https://www.rakuten.com",
                    "portal_type": "cashback",
                    "is_aggregator": false,
                    "is_popular": true,
                    "display_order": 1
                  },
                  {
                    "id": "23456789-2345-2345-2345-234567890123",
                    "slug": "topcashback",
                    "name": "TopCashback",
                    "portal_type": "cashback",
                    "is_popular": true,
                    "display_order": 2
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/credit-cards": {
      "get": {
        "summary": "List credit cards with cashback rates",
        "description": "Returns credit cards with their issuer, network, base cashback rate, category bonuses, and annual fee. Useful for stacking analysis: cross-reference a store's category with each card's category_bonuses[].category to find the best card to pay with.",
        "responses": {
          "200": {
            "description": "Credit cards",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": "card-1",
                    "issuer": "Chase",
                    "card_name": "Freedom Unlimited",
                    "network": "Visa",
                    "base_cashback_rate": 1.5,
                    "annual_fee": 0,
                    "category_bonuses": [
                      { "category": "Travel", "rate": 5 },
                      { "category": "Dining", "rate": 3 }
                    ]
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/deals": {
      "get": {
        "summary": "List active deals and coupon codes",
        "description": "Hand-picked deals with optional expiration. Sorted by featured then recency.",
        "responses": {
          "200": {
            "description": "Deals",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": 42,
                    "store_slug": "amazon",
                    "store_name": "Amazon",
                    "title": "20% off select Amazon devices",
                    "description": "Echo Dot, Fire TV Stick, Kindle e-readers",
                    "code": null,
                    "url": "https://cashbackall.com/store/amazon",
                    "expires_at": "2026-05-31T23:59:59Z",
                    "featured": true
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/categories": {
      "get": {
        "summary": "List store categories",
        "description": "Returns the active category list used for store filtering (Electronics, Fashion, Travel, etc.).",
        "responses": {
          "200": {
            "description": "Categories",
            "content": {
              "application/json": {
                "example": ["Electronics", "Fashion", "Home", "Retail", "Travel", "Food"]
              }
            }
          }
        }
      }
    },
    "/api/stores": {
      "get": {
        "summary": "Search and list stores",
        "description": "Paginated store list with optional search and category filter. For one-store deep dives, use /api/stores/{slug} instead — same data shape but skips pagination overhead.",
        "parameters": [
          { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Store name fuzzy match (uses pg_trgm)", "example": "amazon" },
          { "name": "category", "in": "query", "schema": { "type": "string" }, "description": "Filter by category slug", "example": "Electronics" },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "default": 20, "maximum": 100 } },
          { "name": "slug", "in": "query", "schema": { "type": "string" }, "description": "Single-slug fetch (returns array of length 1 when match)", "example": "amazon" }
        ],
        "responses": {
          "200": {
            "description": "Matching stores",
            "content": {
              "application/json": {
                "example": [
                  {
                    "id": "store-uuid-1",
                    "slug": "amazon",
                    "name": "amazon",
                    "category": "Retail",
                    "logo_url": "/logos/amazon.png",
                    "rates": [
                      { "rate": "8%", "portal": { "name": "Rakuten", "slug": "rakuten" }, "verified_at": "2026-05-13T10:00:00Z" },
                      { "rate": "6%", "portal": { "name": "TopCashback", "slug": "topcashback" }, "verified_at": "2026-05-13T09:30:00Z" }
                    ],
                    "bestRate": "8%",
                    "bestPortal": "Rakuten",
                    "rateCount": 2
                  }
                ]
              }
            }
          }
        }
      }
    },
    "/api/stores/{slug}/rate-history": {
      "get": {
        "summary": "Cashback rate history for a store",
        "description": "Time-series of historical cashback rates per portal for the given store. Useful for answering 'is this rate unusually high right now?' type questions.",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "type": "string" }, "example": "amazon" },
          { "name": "days", "in": "query", "schema": { "type": "integer", "default": 30, "maximum": 365 } }
        ],
        "responses": {
          "200": {
            "description": "Rate history",
            "content": {
              "application/json": {
                "example": [
                  { "portal": "Rakuten", "rate": "8%", "changed_at": "2026-05-10T00:00:00Z" },
                  { "portal": "Rakuten", "rate": "6%", "changed_at": "2026-04-25T00:00:00Z" },
                  { "portal": "TopCashback", "rate": "6%", "changed_at": "2026-05-01T00:00:00Z" }
                ]
              }
            }
          },
          "404": { "description": "Store not found" }
        }
      }
    },
    "/api/version": {
      "get": {
        "summary": "Build and version metadata",
        "description": "Returns the deployed git SHA + build timestamp.",
        "responses": {
          "200": {
            "description": "Version info",
            "content": {
              "application/json": {
                "example": { "sha": "abc1234", "builtAt": "2026-05-13T08:00:00Z" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Portal": {
        "type": "object",
        "required": ["id", "slug", "name"],
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "slug": { "type": "string", "example": "rakuten" },
          "name": { "type": "string", "example": "Rakuten" },
          "logo_url": { "type": "string", "format": "uri", "nullable": true },
          "website_url": { "type": "string", "format": "uri", "nullable": true },
          "portal_type": { "type": "string", "enum": ["cashback", "rewards", "aggregator"] },
          "is_aggregator": { "type": "boolean" },
          "is_popular": { "type": "boolean" },
          "display_order": { "type": "integer" }
        }
      },
      "StoreRate": {
        "type": "object",
        "properties": {
          "rate": { "type": "string", "example": "8%", "description": "Rate text as scraped — typically a percentage but can be a fixed amount ('$15') or 'up to 10%' for tiered rates." },
          "bonus": { "type": "string", "nullable": true },
          "verified_at": { "type": "string", "format": "date-time" },
          "portal": { "type": "object", "properties": { "name": { "type": "string" }, "slug": { "type": "string" } } }
        }
      },
      "Store": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "format": "uuid" },
          "slug": { "type": "string" },
          "name": { "type": "string" },
          "category": { "type": "string", "nullable": true },
          "logo_url": { "type": "string", "format": "uri", "nullable": true },
          "rates": { "type": "array", "items": { "$ref": "#/components/schemas/StoreRate" } },
          "bestRate": { "type": "string", "nullable": true },
          "bestPortal": { "type": "string", "nullable": true },
          "rateCount": { "type": "integer" }
        }
      }
    },
    "headers": {
      "RateLimitLimit": {
        "description": "Total requests allowed per window (per IP).",
        "schema": { "type": "integer", "example": 60 }
      },
      "RateLimitRemaining": {
        "description": "Requests remaining in the current window.",
        "schema": { "type": "integer", "example": 42 }
      },
      "RateLimitReset": {
        "description": "Unix timestamp (seconds) when the current window resets.",
        "schema": { "type": "integer" }
      },
      "XRequestId": {
        "description": "Request correlation ID — echo this in support tickets to help us trace a specific request through the logs.",
        "schema": { "type": "string", "format": "uuid" }
      }
    }
  }
}
