{
  "openapi": "3.1.0",
  "info": {
    "title": "Pulse — Open Compute-Pricing API",
    "summary": "Daily-regenerated GPU and inference-token pricing indices.",
    "description": "Free, public, no-authentication-required JSON endpoints for the Pulse compute-pricing reference. Methodology is fully public and versioned; per-provider observations are redistributed under CC-BY 4.0. See https://pulsebenchmarks.com/llms.txt for an agent-oriented narrative spec.",
    "version": "1.0.0",
    "contact": {
      "name": "Pulse Benchmarks",
      "email": "methodology@pulsebenchmarks.com",
      "url": "https://pulsebenchmarks.com/"
    },
    "license": {
      "name": "CC-BY 4.0 (data) / Apache 2.0 (code)",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "termsOfService": "https://pulsebenchmarks.com/open/"
  },
  "servers": [
    { "url": "https://pulsebenchmarks.com", "description": "Production" }
  ],
  "tags": [
    { "name": "indices",       "description": "Published index values" },
    { "name": "data",          "description": "Bulk and per-series data downloads" },
    { "name": "status",        "description": "Pipeline freshness and provider health" },
    { "name": "newsletter",    "description": "Optional monthly index update" }
  ],
  "paths": {
    "/api/indices": {
      "get": {
        "tags": ["indices"],
        "operationId": "listIndices",
        "summary": "List all published indices with current values",
        "description": "Returns a summary entry per series with the latest median, freshness, status, and methodology version.",
        "responses": {
          "200": {
            "description": "Index summary",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/IndexSummaryEnvelope" },
                "examples": {
                  "live": {
                    "summary": "Three of the headline series",
                    "value": {
                      "generated_at": "2026-04-25T18:00:00Z",
                      "indices": [
                        { "slug": "h100-sxm-hyperscaler-od", "name": "Pulse H100 SXM Hyperscaler OD", "value": 10.4896, "unit": "USD per GPU-hour", "assessed_at": "2026-04-25T18:00:00Z", "age_days": 0, "provider_count": 4, "is_carried_forward": false, "data_quality": "live", "status": "published" },
                        { "slug": "h100-sxm-neocloud-od",    "name": "Pulse H100 SXM Neocloud OD",    "value": 2.89,     "unit": "USD per GPU-hour", "assessed_at": "2026-04-25T18:00:00Z", "age_days": 0, "provider_count": 5, "is_carried_forward": false, "data_quality": "live", "status": "published" },
                        { "slug": "inference-token-index",   "name": "Pulse Inference Token Index",   "value": 0.19125,  "unit": "USD per million tokens", "anchor_series": "llama_3_3_70b_instruct_fp8_us", "assessed_at": "2026-04-19T18:00:00Z", "age_days": 6, "provider_count": 6, "is_carried_forward": false, "data_quality": "live", "status": "provisional" }
                      ]
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/indices/{slug}": {
      "get": {
        "tags": ["indices"],
        "operationId": "getSeries",
        "summary": "Full series payload for one index",
        "description": "Returns metadata, the gated headline daily series, the per-provider observations behind it, and the latest contributing-provider list.",
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": { "$ref": "#/components/schemas/SeriesSlug" },
            "description": "Stable index slug. See /api/indices for the full list."
          }
        ],
        "responses": {
          "200": {
            "description": "Series payload",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/SeriesPayload" }
              }
            }
          },
          "404": { "description": "Unknown slug" }
        }
      }
    },
    "/api/status": {
      "get": {
        "tags": ["status"],
        "operationId": "getStatus",
        "summary": "Pipeline and per-provider status",
        "responses": {
          "200": {
            "description": "Status report",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/StatusReport" }
              }
            }
          }
        }
      }
    },
    "/data_export.json": {
      "get": {
        "tags": ["data"],
        "operationId": "bulkExport",
        "summary": "Complete underlying dataset",
        "description": "~13 MB. Per-provider price assessments, raw collection logs, supply observations, stock observations, capacity forecasts, plus provider and GPU-model registries.",
        "responses": {
          "200": {
            "description": "Bulk export",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BulkExport" } } }
          }
        }
      }
    },
    "/data/{slug}.json": {
      "get": {
        "tags": ["data"],
        "operationId": "getSeriesJson",
        "summary": "Per-series JSON download",
        "description": "Identical payload to /api/indices/{slug}; served from Cloudflare Pages with edge caching.",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/SeriesSlug" } }
        ],
        "responses": {
          "200": { "description": "Series JSON", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SeriesPayload" } } } }
        }
      }
    },
    "/data/{slug}.csv": {
      "get": {
        "tags": ["data"],
        "operationId": "getSeriesCsv",
        "summary": "Per-series CSV download",
        "description": "Daily series in CSV. Columns: assessed_at, value, provider_count, p25, p75, is_carried_forward, data_quality, status, note.",
        "parameters": [
          { "name": "slug", "in": "path", "required": true, "schema": { "$ref": "#/components/schemas/SeriesSlug" } }
        ],
        "responses": {
          "200": { "description": "CSV", "content": { "text/csv": { "schema": { "type": "string" } } } }
        }
      }
    },
    "/api/subscribe": {
      "post": {
        "tags": ["newsletter"],
        "operationId": "subscribeNewsletter",
        "summary": "Newsletter signup (double opt-in)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Verification email queued",
            "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "already": { "type": "boolean" } } } } }
          },
          "400": { "description": "Invalid email" },
          "502": { "description": "Mail provider failure" }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "SeriesSlug": {
        "type": "string",
        "description": "Stable index slug. URL component for /indices/{slug}/, /methodology/{slug}/v1-0/, /api/indices/{slug}, /data/{slug}.json|.csv.",
        "enum": [
          "inference-token-index",
          "h100-sxm-hyperscaler-od",
          "h100-sxm-neocloud-od",
          "a100-80gb-hyperscaler-od",
          "a100-80gb-neocloud-od",
          "b200-neocloud-od",
          "h200-141gb-neocloud-od",
          "h100-pcie-neocloud-od",
          "a100-80gb-neocloud-spot"
        ]
      },
      "DataQuality": {
        "type": "string",
        "enum": ["live", "reconstructed", "mixed", "preliminary", "unknown"],
        "description": "live = collected directly from a provider API; reconstructed = backfilled from a primary-source archive (Wayback, blog post, press release); mixed = some live, some reconstructed; preliminary = methodology version below 1.0."
      },
      "IndexStatus": {
        "type": "string",
        "enum": ["published", "caveated", "provisional", "raw_only", "no-data"],
        "description": "published = meets methodology publishability threshold; caveated = thin-data warning (neocloud n=2 only); provisional = ITI series with 3-4 commodity hosts; raw_only = ITI series with <3 hosts."
      },
      "DailyRow": {
        "type": "object",
        "required": ["assessed_at", "value", "provider_count"],
        "properties": {
          "assessed_at":        { "type": "string", "format": "date-time" },
          "value":              { "type": "number", "description": "Headline median in the series unit." },
          "provider_count":     { "type": "integer" },
          "p25":                { "type": ["number", "null"] },
          "p75":                { "type": ["number", "null"] },
          "is_carried_forward": { "type": "boolean", "description": "True if any contributing provider value was carried forward from a recent prior collection (within the 3-day staleness window)." },
          "data_quality":       { "$ref": "#/components/schemas/DataQuality" },
          "status":             { "$ref": "#/components/schemas/IndexStatus" },
          "note":               { "type": ["string", "null"] }
        }
      },
      "ContributingProvider": {
        "type": "object",
        "properties": {
          "provider":            { "type": "string" },
          "price":               { "type": "number" },
          "is_carried_forward":  { "type": "boolean" },
          "source_date":         { "type": "string", "format": "date" },
          "methodology_version": { "type": "string" }
        }
      },
      "Observation": {
        "type": "object",
        "properties": {
          "assessed_at":         { "type": "string", "format": "date-time" },
          "provider_id":         { "type": "string" },
          "provider":            { "type": "string" },
          "price":               { "type": "number" },
          "methodology_version": { "type": "string" }
        }
      },
      "SeriesPayload": {
        "type": "object",
        "required": ["slug", "name", "unit", "methodology_version", "license", "generated_at", "series"],
        "properties": {
          "slug":                          { "$ref": "#/components/schemas/SeriesSlug" },
          "name":                          { "type": "string" },
          "unit":                          { "type": "string", "examples": ["USD per GPU-hour", "USD per million tokens"] },
          "methodology_version":           { "type": "string", "examples": ["v1.0"] },
          "methodology_url":               { "type": "string", "format": "uri" },
          "index_url":                     { "type": "string", "format": "uri" },
          "license":                       { "type": "string", "examples": ["CC-BY 4.0"] },
          "generated_at":                  { "type": "string", "format": "date-time" },
          "contributing_providers_latest": { "type": "array", "items": { "$ref": "#/components/schemas/ContributingProvider" } },
          "series":                        { "type": "array", "items": { "$ref": "#/components/schemas/DailyRow" } },
          "observations":                  { "type": "array", "items": { "$ref": "#/components/schemas/Observation" }, "description": "Per-provider per-date raw observations including dates that fell below the publishability threshold. Use these to chart the full history; use `series` for the gated headline median." }
        }
      },
      "IndexSummaryEntry": {
        "type": "object",
        "required": ["slug", "name"],
        "properties": {
          "slug":               { "$ref": "#/components/schemas/SeriesSlug" },
          "name":               { "type": "string" },
          "value":              { "type": ["number", "null"] },
          "unit":               { "type": "string" },
          "assessed_at":        { "type": ["string", "null"], "format": "date-time" },
          "age_days":           { "type": "integer" },
          "provider_count":     { "type": "integer" },
          "is_carried_forward": { "type": "boolean" },
          "data_quality":       { "$ref": "#/components/schemas/DataQuality" },
          "status":             { "$ref": "#/components/schemas/IndexStatus" },
          "anchor_series":      { "type": "string", "description": "Only set for inference-token-index — the v1.0 anchor named-model series." }
        }
      },
      "IndexSummaryEnvelope": {
        "type": "object",
        "required": ["generated_at", "indices"],
        "properties": {
          "generated_at": { "type": "string", "format": "date-time" },
          "indices":      { "type": "array", "items": { "$ref": "#/components/schemas/IndexSummaryEntry" } }
        }
      },
      "ProviderStatus": {
        "type": "object",
        "properties": {
          "provider_id":     { "type": "string" },
          "provider_name":   { "type": "string" },
          "last_success_at": { "type": ["string", "null"], "format": "date-time" },
          "last_attempt_at": { "type": ["string", "null"], "format": "date-time" },
          "successes_30d":   { "type": "integer" },
          "status":          { "type": "string", "enum": ["green", "yellow", "red", "unknown"] }
        }
      },
      "IndexHealth": {
        "type": "object",
        "properties": {
          "slug":          { "type": "string" },
          "name":          { "type": "string" },
          "status":        { "type": "string", "enum": ["green", "yellow", "red", "no-data"] },
          "last_value_at": { "type": ["string", "null"], "format": "date-time" },
          "data_quality":  { "$ref": "#/components/schemas/DataQuality" },
          "value":         { "type": ["number", "null"] }
        }
      },
      "StatusReport": {
        "type": "object",
        "properties": {
          "generated_at":         { "type": "string", "format": "date-time" },
          "overall":              { "type": "string", "enum": ["green", "yellow", "red"] },
          "providers":            { "type": "array", "items": { "$ref": "#/components/schemas/ProviderStatus" } },
          "indices":              { "type": "array", "items": { "$ref": "#/components/schemas/IndexHealth" } },
          "open_incidents":       { "type": "array", "items": { "type": "object" } },
          "resolved_incidents":   { "type": "array", "items": { "type": "object" } }
        }
      },
      "BulkExport": {
        "type": "object",
        "properties": {
          "assessments":         { "type": "array", "description": "Per-provider price assessments." },
          "raw_collections":     { "type": "array", "description": "Every API call ever made." },
          "collection_runs":     { "type": "array" },
          "providers":           { "type": "array" },
          "gpu_models":          { "type": "array" },
          "instance_gpu_map":    { "type": "array" },
          "supply_observations": { "type": "array", "description": "Vast.ai marketplace utilisation." },
          "stock_observations":  { "type": "array", "description": "Lambda / RunPod / DataCrunch / Hyperstack stock state." },
          "capacity_forecasts":  { "type": "array", "description": "Hyperstack 7d/30d projections." },
          "date_range":          { "type": "object", "properties": { "min": { "type": "string", "format": "date-time" }, "max": { "type": "string", "format": "date-time" } } }
        }
      }
    }
  }
}
