{
  "openapi": "3.0.3",
  "info": {
    "title": "Gas Fee Predictor API",
    "description": "Free public JSON API for live Ethereum mainnet + Layer 2 gas fees, with active failover across multiple public RPCs, pattern-based 24h forecasts, and full wallet-fee estimates including L1 data fees on OP Stack chains. No API key, no signup. Methodology: https://gasfeepredictor.com/methodology",
    "version": "1.0.0",
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "contact": {
      "name": "Gas Fee Predictor",
      "url": "https://gasfeepredictor.com"
    }
  },
  "servers": [
    {
      "url": "https://api.gasfeepredictor.com",
      "description": "Production (DNS-only subdomain — reachable from servers, workers, and curl; not behind the bot challenge)"
    }
  ],
  "tags": [
    { "name": "mainnet", "description": "Ethereum mainnet gas data" },
    { "name": "l2", "description": "Layer 2 (Arbitrum, Optimism, Base, Polygon) gas data" },
    { "name": "price", "description": "ETH/USD price data" },
    { "name": "history", "description": "Historical gas data" },
    { "name": "forecast", "description": "Pattern-based 24h gas forecasts" }
  ],
  "paths": {
    "/api/dashboard": {
      "get": {
        "tags": ["mainnet", "forecast", "price"],
        "summary": "Aggregated homepage payload",
        "description": "Single round-trip for the data the homepage dashboard needs: current Ethereum mainnet gas, ETH/USD price, 24h prediction series, next-best transaction window, and a compact recent-history series. Use this when you need most of the gas data; use the individual endpoints when you want a thinner payload.",
        "responses": {
          "200": {
            "description": "Live aggregated payload",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/DashboardResponse" }
              }
            }
          }
        }
      }
    },
    "/api/eth-price": {
      "get": {
        "tags": ["price"],
        "summary": "Live ETH/USD price",
        "description": "Current Ethereum price in USD with 24h change and 7-day hourly sparkline. Multi-source fallback chain: CoinGecko → Binance.US → Coinbase. On cold-start failure returns HTTP 200 with usd:null and source:'unavailable' rather than 5xx, so consumers can render gracefully.",
        "responses": {
          "200": {
            "description": "ETH price snapshot",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/EthPriceResponse" }
              }
            }
          }
        }
      }
    },
    "/api/gas-predictions": {
      "get": {
        "tags": ["mainnet", "forecast"],
        "summary": "Mainnet gas snapshot + 24h forecast",
        "description": "Live mainnet gas (low/average/high tiers) plus a pattern-based forecast of hourly gas prices with confidence scores and isLowFeeWindow flags. Use this when you need the full forecast without the dashboard's extra fields.",
        "parameters": [
          {
            "name": "timeframe",
            "in": "query",
            "schema": { "type": "string", "enum": ["6h", "12h", "24h", "7d"], "default": "24h" },
            "description": "Forecast horizon"
          }
        ],
        "responses": {
          "200": {
            "description": "Gas snapshot + predictions",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/GasPredictionsResponse" }
              }
            }
          }
        }
      }
    },
    "/api/gas-history": {
      "get": {
        "tags": ["mainnet", "history"],
        "summary": "Historical mainnet gas prices",
        "description": "Bucketed historical gas prices for the requested window. Sourced from a 90-second-cadence writer persisting each gas snapshot to Postgres.",
        "parameters": [
          {
            "name": "range",
            "in": "query",
            "schema": { "type": "string", "enum": ["10m", "30m", "2h", "6h", "1d", "7d", "30d"], "default": "1d" },
            "description": "Look-back window. Bucket size scales with range to keep payloads under ~300 points."
          }
        ],
        "responses": {
          "200": {
            "description": "Historical gas series",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/GasHistoryResponse" }
              }
            }
          }
        }
      }
    },
    "/api/l2-gas": {
      "get": {
        "tags": ["l2"],
        "summary": "Live L2 gas across Arbitrum, Optimism, Base, Polygon",
        "description": "Per-network execution gas + full wallet-fee estimate. For OP Stack chains (Optimism, Base), estimatedL1DataFeeUsd is queried live from the GasPriceOracle predeploy and added to executionGasCostUsd. For Arbitrum, Nitro already bundles L1 calldata into eth_gasPrice. For Polygon (sidechain), no L1 fee applies.",
        "responses": {
          "200": {
            "description": "L2 gas snapshot",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/L2GasResponse" }
              }
            }
          }
        }
      }
    },
    "/api/l2-gas-history": {
      "get": {
        "tags": ["l2", "history"],
        "summary": "Historical L2 gas prices",
        "description": "90-second-cadence samples for the requested L2 network and window, persisted to Postgres.",
        "parameters": [
          {
            "name": "network",
            "in": "query",
            "required": true,
            "schema": { "type": "string", "enum": ["arbitrum", "optimism", "base", "polygon"] }
          },
          {
            "name": "hours",
            "in": "query",
            "required": true,
            "schema": { "type": "integer", "enum": [1, 6, 24, 168] }
          }
        ],
        "responses": {
          "200": {
            "description": "L2 gas history",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/L2GasHistoryResponse" }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ApiMeta": {
        "type": "object",
        "description": "Every public endpoint includes these fields. citation is a copy-paste-ready attribution string for AI agents and integrators. tier indicates the API tier (currently always 'free').",
        "properties": {
          "citation": {
            "type": "string",
            "description": "Stable attribution string. Format: 'Gas data from Gas Fee Predictor, gasfeepredictor.com, updated <ISO-8601>'.",
            "example": "Gas data from Gas Fee Predictor, gasfeepredictor.com, updated 2026-05-26T16:30:00Z"
          },
          "tier": {
            "type": "string",
            "enum": ["free"],
            "description": "API tier. Currently 'free' for all requests."
          }
        },
        "required": ["citation", "tier"]
      },
      "GasTier": {
        "type": "object",
        "properties": {
          "low": { "type": "number", "description": "Low-priority tier (slow inclusion)" },
          "average": { "type": "number", "description": "Standard tier (typical inclusion)" },
          "high": { "type": "number", "description": "High tier (fast inclusion, ≈ Blocknative 99% confidence)" }
        }
      },
      "Prediction": {
        "type": "object",
        "properties": {
          "timestamp": { "type": "string", "format": "date-time" },
          "low": { "type": "number" },
          "average": { "type": "number" },
          "high": { "type": "number" },
          "isLowFeeWindow": { "type": "boolean", "description": "True if this hour is in a predicted low-fee window" },
          "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
        }
      },
      "NextBestWindow": {
        "type": "object",
        "properties": {
          "timestamp": { "type": "string", "format": "date-time" },
          "gasPrices": { "$ref": "#/components/schemas/GasTier" },
          "confidence": { "type": "number", "nullable": true, "minimum": 0, "maximum": 1 }
        }
      },
      "Decision": {
        "type": "object",
        "properties": {
          "recommendation": { "type": "string", "enum": ["wait", "send_now"] },
          "expectedSavingsPct": { "type": "number" },
          "expectedGas": { "type": "number" },
          "nextBestEtaMinutes": { "type": "number" },
          "nextBestAt": { "type": "string", "format": "date-time" },
          "confidence": { "type": "number", "minimum": 0, "maximum": 1 }
        }
      },
      "DashboardResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiMeta" },
          {
            "type": "object",
            "properties": {
              "currentGas": {
                "allOf": [
                  { "$ref": "#/components/schemas/GasTier" },
                  { "type": "object", "properties": { "source": { "type": "string" } } }
                ]
              },
              "decision": { "$ref": "#/components/schemas/Decision" },
              "ethPrice": { "$ref": "#/components/schemas/EthPriceCompact" },
              "nextBestWindow": { "$ref": "#/components/schemas/NextBestWindow", "nullable": true },
              "predictions": { "type": "array", "items": { "$ref": "#/components/schemas/Prediction" } },
              "compactHistory": { "type": "array", "items": { "type": "object" } },
              "lastUpdated": { "type": "string", "format": "date-time" }
            }
          }
        ]
      },
      "EthPriceCompact": {
        "type": "object",
        "properties": {
          "usd": { "type": "number", "nullable": true },
          "change_24h": { "type": "number", "nullable": true },
          "updatedAt": { "type": "string", "format": "date-time" }
        }
      },
      "EthPriceResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiMeta" },
          {
            "type": "object",
            "properties": {
              "usd": { "type": "number", "nullable": true, "description": "ETH price in USD. Null in soft-fail mode (all upstreams down on cold start)." },
              "change_24h": { "type": "number", "nullable": true },
              "sparkline_7d": { "type": "array", "items": { "type": "number" }, "description": "168 hourly values" },
              "updatedAt": { "type": "string", "format": "date-time" },
              "priceSource": {
                "type": "string",
                "enum": ["coingecko", "binance", "coinbase"],
                "description": "Which upstream successfully served the price field. Sparkline always from CoinGecko when present."
              },
              "source": { "type": "string", "description": "Cache/source label: cache | coingecko | binance | coinbase | stale-timeout | stale-cooldown | stale-error | unavailable" }
            }
          }
        ]
      },
      "GasPredictionsResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiMeta" },
          {
            "type": "object",
            "properties": {
              "current": {
                "allOf": [
                  { "$ref": "#/components/schemas/GasTier" },
                  { "type": "object", "properties": { "source": { "type": "string" } } }
                ]
              },
              "historical": { "type": "array", "items": { "type": "object" } },
              "predictions": { "type": "array", "items": { "$ref": "#/components/schemas/Prediction" } },
              "nextBestTime": { "type": "object", "nullable": true },
              "decision": { "$ref": "#/components/schemas/Decision" },
              "timeframe": { "type": "string" },
              "dataPoints": { "type": "integer" },
              "lastUpdated": { "type": "string", "format": "date-time" },
              "usingFallbackData": { "type": "boolean" }
            }
          }
        ]
      },
      "GasHistoryResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiMeta" },
          {
            "type": "object",
            "properties": {
              "range": { "type": "string" },
              "points": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "timestamp": { "type": "string", "format": "date-time" },
                    "gasPrice": { "type": "number" }
                  }
                }
              },
              "meta": {
                "type": "object",
                "properties": {
                  "requestedRange": { "type": "string" },
                  "renderedRangeStart": { "type": "string", "format": "date-time", "nullable": true },
                  "renderedRangeEnd": { "type": "string", "format": "date-time", "nullable": true },
                  "pointCount": { "type": "integer" },
                  "source": { "type": "string" }
                }
              }
            }
          }
        ]
      },
      "L2NetworkReading": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "enum": ["arbitrum", "optimism", "base", "polygon"] },
          "name": { "type": "string" },
          "nativeToken": { "type": "string", "enum": ["ETH", "POL"] },
          "gasPriceGwei": { "type": "number" },
          "nativeUsd": { "type": "number" },
          "executionGasCostUsd": { "type": "number", "description": "L2 execution gas cost for a 21,000-gas transfer" },
          "estimatedL1DataFeeUsd": {
            "type": "number",
            "nullable": true,
            "description": "L1 data fee from GasPriceOracle (OP Stack only). null for Arbitrum (folded into eth_gasPrice) and Polygon (sidechain, no L1)."
          },
          "estimatedWalletFeeUsd": {
            "type": "number",
            "nullable": true,
            "description": "Full estimated wallet fee = executionGasCostUsd + estimatedL1DataFeeUsd. For Arbitrum/Polygon, equals executionGasCostUsd."
          },
          "feeCompleteness": { "type": "string", "enum": ["execution_only", "full_estimate"] },
          "feeModel": { "type": "string", "enum": ["rollup_arbitrum_nitro", "rollup_op_stack", "sidechain"] },
          "blurb": { "type": "string" },
          "feeNote": { "type": "string" }
        }
      },
      "L2GasResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiMeta" },
          {
            "type": "object",
            "properties": {
              "networks": { "type": "array", "items": { "$ref": "#/components/schemas/L2NetworkReading" } },
              "fetchedAt": { "type": "string", "format": "date-time" }
            }
          }
        ]
      },
      "L2GasHistoryResponse": {
        "allOf": [
          { "$ref": "#/components/schemas/ApiMeta" },
          {
            "type": "object",
            "properties": {
              "network": { "type": "string" },
              "hours": { "type": "integer" },
              "points": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "timestamp": { "type": "string", "format": "date-time" },
                    "gas_price_gwei": { "type": "number" },
                    "execution_gas_cost_usd": { "type": "number" }
                  }
                }
              }
            }
          }
        ]
      }
    }
  }
}
