OilPriceAPI Docs
Quick Start
API Reference
  • SDKs and languages
  • Tutorials
  • Articles
  • Documentation directory
  • Quick reference
  • API explorer
  • FAQ
  • Changelog
  • Status
  • Dashboard
GitHub
Quick Start
API Reference
  • SDKs and languages
  • Tutorials
  • Articles
  • Documentation directory
  • Quick reference
  • API explorer
  • FAQ
  • Changelog
  • Status
  • Dashboard
GitHub
  • Interactive Explorer

    • Interactive API Explorer
  • Price Data

    • API Reference
    • Get Latest Prices
    • Historical Prices
    • Batch Prices
    • Excel Latest Price Gateway
    • Price Widget Endpoints
    • Price Utility Endpoints
    • Demo API (No Authentication)
    • Natural Gas Intelligence
  • Commodities

    • List Commodities
    • Get Commodity Details
    • Data Publication & Collection Schedules
  • AI Agents (MCP)

    • Get Market Brief
    • Subscriptions / Watches
    • Agent Subscriptions with MCP
  • Marine Fuels

    • Marine Fuel API
    • List Marine Fuel Ports
    • Get Port Details with Prices
    • Bunker Fuels
    • Maritime Fuels
  • Fuel Surcharges

    • Fuel Surcharge API
  • Premium Endpoints

    • All Prices API - One Call, All Commodities
    • Cushing Oil Storage Intelligence API
    • Drilling Intelligence API
    • Marine Fuels API
    • ICE Brent Futures API
    • Benchmark Close
    • Aviation Fuel Pilot
  • Spreads & Margins

    • Spreads & Margins
    • Crack Spreads
    • European Gasoil Crack
    • Basis Spreads
    • Refining Margins
    • Curve Structure
    • Physical Premiums
  • Market Indicators

    • Market Indicators
    • Fuel Switching
    • Price Context
    • Storage Analytics
    • CFTC Positioning
    • Congressional Trades
    • Market Annotations
  • Futures

    • Futures API
    • ICE Brent Futures
    • ICE WTI Futures
    • Continuous Futures (Brent, WTI)
    • ICE Gas Oil Futures
    • NYMEX Natural Gas Futures
    • ICE EUA Carbon Futures
    • EU Carbon Futures
    • TTF Gas Futures
    • LNG JKM Futures
    • UK Carbon Futures
  • Dark Data (Premium)

    • Energy Intelligence API
    • Rig Counts
    • Well Permits
    • Well Production Beta
    • Drilling Intelligence (Public)
    • Oil Inventories
    • OPEC Production
    • Drilling Productivity
    • Forecasts (STEO)
  • Well Production (Beta)

    • Well Production Data
    • Well Production API Reference
  • Analytics

    • Analytics API
  • Webhooks API

    • Webhooks API Reference
    • Webhook Endpoint Reference
  • Alerts

    • Price Alerts API
  • Account & Billing

    • Account API
    • API Keys
    • Subscriptions
    • Organizations

Historical Prices

Status: ✅ Available | 📈 Time-Series | 🔄 Multiple Intervals

Access historical price data for oil and commodity markets with customizable time ranges and intervals.

Endpoints

MethodEndpointDescription
GET/v1/prices/historicalCustom date range or relative window; daily buckets by default
GET/v1/prices/past_dayRaw spot price points for the past 24 hours, or one calendar day with at=
GET/v1/prices/past_weekRaw spot price points for the past 7 days
GET/v1/prices/past_monthRaw spot price points for the past 30 days
GET/v1/prices/past_yearRaw spot price points for the past 365 days

/v1/prices/historical is the canonical endpoint for full archives. It requires by_code, defaults to interval=daily, and supports up to 500 rows per page. The fixed-window endpoints default to raw collected points and cap raw pages at 100 rows. Publication frequency varies by commodity; a raw point is not necessarily a real-time market tick.

Authentication

See Authentication Guide for API key setup.

Custom Historical Parameters

These parameters apply to GET /v1/prices/historical:

ParameterTypeRequiredDescriptionDefaultExample
by_codestringYesOne code or a comma-separated list—WTI_USD, JET_FUEL_USD
by_typestringNoStored price typeallspot_price
start_datedateNoInclusive UTC start dateplan limit2025-01-01
end_datedateNoInclusive UTC end datenow2025-12-31
paststringNoRelative window when explicit dates are omitted—30d, 6m, 1y
intervalstringNoAggregation interval (see Interval Parameter for alias spellings)dailyraw, hourly, daily, weekly, monthly
pageintegerNoPage number11, 2, 3
per_pageintegerNoRows per page; values above 500 are clamped500100, 500

Fixed-window parameters

These apply to past_day, past_week, past_month and past_year:

ParameterTypeRequiredDescriptionExample
by_codestringYesOne code or a comma-separated listWTI_USD
intervalstringNoAggregation interval (see below); default raw1d, 1w
atdateNopast_day only. Return the points for one UTC calendar day instead of the trailing 24 hours. YYYY-MM-DD; an unparseable value returns 400 "Invalid at format". /v1/prices/YYYY-MM-DD is an alias that serves this lookup directly (no redirect), with the date landing in atat=2026-08-27
as_ofstringNoPoint-in-time view: rows as they stood at that instant, with later source revisions rolled back. ISO 8601 date or datetime, not in the future, and requires interval=raw (aggregates cannot be vintage-corrected row by row). Revisions are tracked from 2026-07-28; a vintage earlier than that returns the rows as first collectedas_of=2026-08-01T00:00:00Z

A vintage request echoes its parameters in two headers:

HeaderValue
X-Vintage-As-OfThe applied instant, UTC ISO 8601 (a bare date becomes its end of day)
X-Vintage-Revision-Coverage-Since2026-07-28 — no revisions before this date are recorded

Historical depth is entitlement-aware even when you omit all date bounds. Use GET /v1/commodities/{code} to see your_access, source cadence, coverage, and direct links to the canonical OpenAPI operation and this guide.

Interval Parameter

The interval parameter controls time-based aggregation for historical data. When specified, prices are averaged within each time bucket, reducing data transfer and improving performance for charting and dashboard applications.

IntervalDescriptionAggregationUse Case
rawNo aggregation (default on fixed-window endpoints)Individual price pointsFull granularity, detailed analysis
hourlyHourly aggregationAverage price per hourIntraday analysis, short-term trends
dailyDaily aggregationAverage price per dayDaily charts, week-over-week comparison
weeklyWeekly aggregationAverage price per weekMonthly/quarterly charts, medium-term trends
monthlyMonthly aggregationAverage price per monthYearly charts, long-term trends

Every historical endpoint accepts the same alias spellings per family, case-insensitively: 1h/h/hour/1hour for hourly; 1d/d/day/1day for daily; 1w/w/week/1week for weekly; 1m/m/month/1month for monthly. An unknown spelling on /v1/prices/historical returns 400 listing valid_intervals. Some endpoints support fewer families (futures history has no hourly bars); the error names what that endpoint accepts.

When an interval is supplied, each returned point has type set to the bucket average (e.g. daily_average), source set to aggregated, and an added price_type field.

Benefits:

  • Reduced Data Transfer: Fewer data points for the same time range (e.g., 30 days ≈ 30 daily averages vs. several thousand raw ~5–10 minute points)
  • Lower Rate Limit Usage: Aggregated responses use the same rate limit as raw data
  • Optimized for Charting: Pre-aggregated data is ideal for time-series visualizations
  • Consistent Formatting: All prices rounded to 2 decimal places for currency consistency

Response

Success (200) - Raw Data

data.prices is an array of raw spot points, roughly 5–10 minutes apart:

{
  "status": "success",
  "data": {
    "prices": [
      {
        "price": 67.84,
        "formatted": "$67.84",
        "currency": "USD",
        "code": "WTI_USD",
        "created_at": "2026-07-02T13:54:43.160Z",
        "updated_at": "2026-07-02T13:54:43.160Z",
        "type": "spot_price",
        "unit": "barrel",
        "source": "market_reporting"
      },
      {
        "price": 67.79,
        "formatted": "$67.79",
        "currency": "USD",
        "code": "WTI_USD",
        "created_at": "2026-07-02T13:46:11.402Z",
        "updated_at": "2026-07-02T13:46:11.402Z",
        "type": "spot_price",
        "unit": "barrel",
        "source": "market_reporting"
      }
    ]
  }
}

Success (200) - With Interval Aggregation

When using the interval parameter, points are bucket averages — type becomes the average type, source is aggregated, and a price_type field is added:

{
  "status": "success",
  "data": {
    "prices": [
      {
        "price": 67.94,
        "formatted": "$67.94",
        "currency": "USD",
        "code": "WTI_USD",
        "created_at": "2026-07-02T00:00:00.000Z",
        "type": "daily_average",
        "price_type": "daily_average",
        "source": "aggregated"
      },
      {
        "price": 68.41,
        "formatted": "$68.41",
        "currency": "USD",
        "code": "WTI_USD",
        "created_at": "2026-07-01T00:00:00.000Z",
        "type": "daily_average",
        "price_type": "daily_average",
        "source": "aggregated"
      }
    ]
  }
}

Response Fields

FieldTypeDescription
pricenumberPrice value (rounded to 2 decimal places)
formattedstringCurrency-formatted price with symbol
currencystringCurrency code (USD, EUR, GBP)
codestringCommodity code
created_atstringISO 8601 timestamp (UTC)
observed_atstringISO 8601 source observation timestamp when available; useful for daily official-source records
source_datestringDate-only source reference date when available, such as OPEC Basket daily values
updated_atstringISO 8601 timestamp of the last update (UTC) — raw points only
unitstringUnit of measure (e.g. barrel) — raw points only
typestringPrice type: spot_price for raw, or the bucket type (e.g. daily_average) for aggregated
price_typestringAdded only on aggregated points; mirrors the bucket average type
sourcestringData source: aggregated for interval data, or a source label (e.g. eia, market_reporting) for raw data

Alongside data.prices, a response may carry a data.metadata block:

FieldTypeDescription
metadata.instrument_disclosuresarrayPresent when a requested code is a calendar-month average swap (SINGAPORE_JET_KEROSENE_USD, SINGAPORE_MOGAS_92_USD): one disclosure per instrument, not per row. Same shape as instrument_disclosure on Latest Prices. Do not average these series into a monthly figure
metadata.quarantineobjectPresent when verified-unreliable historical values were withheld from the response — see below

Withheld values (metadata.quarantine)

A small number of dates carry values that were verified to be wrong at the source or at ingestion (for example an intraday scaling error contaminating a daily average). Those dates are excluded from every historical response rather than served; the stored rows are not deleted. When the exclusion touched your window the response says so:

{
  "status": "success",
  "data": {
    "prices": ["…"],
    "metadata": {
      "quarantine": {
        "applied": true,
        "excluded_dates_count": 1,
        "codes": ["BRENT_CRUDE_USD"],
        "entries": [
          { "code": "BRENT_CRUDE_USD", "date": "2021-03-11", "reason": "intraday scaling outlier contaminated the published daily aggregate" }
        ],
        "entries_truncated": false,
        "message": "Verified unreliable historical values were withheld from this response; no source rows were deleted.",
        "recovery": "…"
      }
    }
  }
}

entries[] lists the withheld code/date/reason triples; entries_truncated is true when the list was capped. The block is absent when nothing in your window was withheld.

Pagination

Historical endpoints return paginated results for performance. /v1/prices/historical defaults to and caps pages at 500 rows; fixed-window raw endpoints cap pages at 100 rows. Page through larger ranges with page=N. The total-count header is X-Total (not X-Total-Count).

HeaderDescriptionExample
X-TotalTotal number of records2016
X-Total-PagesTotal number of pages21
X-PageCurrent page number1
X-Per-PageApplied records per page500
X-Vintage-As-OfOnly with as_of=: the applied instant2026-08-01T23:59:59Z
X-Vintage-Revision-Coverage-SinceOnly with as_of=: first date with revision tracking2026-07-28

This endpoint does not send a Link header. Page through results with X-Total-Pages and page=N.

OPEC Reference Basket

Use OPEC_BASKET_USD for the official OPEC Reference Basket price. The series is sourced from OPEC's official daily XML archive, uses source: "opec.org", and carries source_date for the OPEC reference date.

curl "https://api.oilpriceapi.com/v1/prices/historical?by_code=OPEC_BASKET_USD&start_date=2003-01-01&interval=daily" \
  -H "Authorization: Token YOUR_API_KEY"

OPEC Basket historical data is available on paid plans through the normal historical endpoints. Plan historical-depth limits still apply.

Examples

Basic Usage

# Get past 24 hours of raw WTI data (all individual price points)
curl "https://api.oilpriceapi.com/v1/prices/past_day?by_code=WTI_USD" \
  -H "Authorization: Token YOUR_API_KEY"

# Get past week with pagination
curl "https://api.oilpriceapi.com/v1/prices/past_week?by_code=WTI_USD&page=1&per_page=50" \
  -H "Authorization: Token YOUR_API_KEY"

# Get CSV format
curl "https://api.oilpriceapi.com/v1/prices/past_year?by_code=WTI_USD&format=csv" \
  -H "Authorization: Token YOUR_API_KEY"

Using Interval Aggregation

# Get past month as daily averages (~30 points instead of thousands of raw points)
curl "https://api.oilpriceapi.com/v1/prices/past_month?by_code=BRENT_CRUDE_USD&interval=1d" \
  -H "Authorization: Token YOUR_API_KEY"

# Get past year as weekly averages for long-term trending
curl "https://api.oilpriceapi.com/v1/prices/past_year?by_code=WTI_USD&interval=1w" \
  -H "Authorization: Token YOUR_API_KEY"

# Get past week as hourly averages for intraday analysis
curl "https://api.oilpriceapi.com/v1/prices/past_week?by_code=NATURAL_GAS_USD&interval=1h" \
  -H "Authorization: Token YOUR_API_KEY"

# Get past year as monthly averages for annual trends
curl "https://api.oilpriceapi.com/v1/prices/past_year?by_code=BRENT_CRUDE_USD&interval=1m" \
  -H "Authorization: Token YOUR_API_KEY"

JavaScript/TypeScript

// Get past week with daily aggregation
async function getWeeklyPrices() {
  const response = await fetch(
    "https://api.oilpriceapi.com/v1/prices/past_week?by_code=WTI_USD&interval=1d",
    {
      headers: {
        Authorization: "Token YOUR_API_KEY",
      },
    },
  );

  const data = await response.json();
  return data.data.prices; // Returns ~7 daily averages
}

// Get optimized data for charting (monthly averages for past year)
async function getChartData(commodityCode = "WTI_USD") {
  const response = await fetch(
    `https://api.oilpriceapi.com/v1/prices/past_year?by_code=${commodityCode}&interval=1m`,
    {
      headers: { Authorization: "Token YOUR_API_KEY" },
    },
  );

  const data = await response.json();

  // Format for chart libraries (e.g., Chart.js, Recharts)
  return data.data.prices.map((price) => ({
    date: new Date(price.created_at),
    value: price.price,
    formatted: price.formatted,
  }));
}

// Handle pagination for raw (non-aggregated) data
async function getAllRawData(
  endpoint = "past_week",
  commodityCode = "WTI_USD",
) {
  let allData = [];
  let page = 1;
  let totalPages = 1;

  while (page <= totalPages) {
    const response = await fetch(
      `https://api.oilpriceapi.com/v1/prices/${endpoint}?by_code=${commodityCode}&page=${page}`,
      {
        headers: { Authorization: "Token YOUR_API_KEY" },
      },
    );

    totalPages = parseInt(response.headers.get("X-Total-Pages"));
    const data = await response.json();

    if (data.data?.prices) {
      allData.push(...data.data.prices);
    }

    page++;
  }

  return allData;
}

Python

import requests
from datetime import datetime

# Get past month as daily averages
def get_monthly_averages(commodity_code='WTI_USD'):
    url = 'https://api.oilpriceapi.com/v1/prices/past_month'
    headers = {'Authorization': 'Token YOUR_API_KEY'}
    params = {
        'by_code': commodity_code,
        'interval': '1d'  # Daily aggregation
    }

    response = requests.get(url, headers=headers, params=params)
    data = response.json()

    return data['data']['prices']

# Get past year with weekly aggregation for trending
def get_yearly_trend(commodity_code='BRENT_CRUDE_USD'):
    url = 'https://api.oilpriceapi.com/v1/prices/past_year'
    headers = {'Authorization': 'Token YOUR_API_KEY'}
    params = {
        'by_code': commodity_code,
        'interval': '1w'  # Weekly aggregation
    }

    response = requests.get(url, headers=headers, params=params)
    data = response.json()

    # Format for data analysis
    prices = []
    for price in data['data']['prices']:
        prices.append({
            'date': datetime.fromisoformat(price['created_at'].replace('Z', '+00:00')),
            'price': price['price'],
            'type': price['type']
        })

    return prices

Errors

CodeStatusDescription
UNAUTHORIZED401Missing or invalid API key (returned as error.code)
invalid_code400Unknown commodity code (returned under data with status: "fail")
—400as_of rejected: "Invalid as_of: … Use ISO8601 — as_of=2026-06-02 or as_of=2026-06-02T00:00:00Z.", "as_of must not be in the future.", or "as_of requires interval=raw. Aggregated intervals cannot be vintage-corrected row-by-row." (under data.error)
—400at rejected on past_day: "Invalid at format" (under data.error)

Rate Limits

All plans share the same request rate limit of 60 requests per rolling 60-second window per API key. Plans differ by request quota (daily on Free, monthly on paid plans), not by a per-endpoint rate ladder. Bursts within the window are fine. See Rate Limiting for details.

PlanRequest QuotaRequest Rate Limit
Free50 / day60 per rolling 60s
Free Trial (7 days)10,00060 per rolling 60s
Developer10,000 / month60 per rolling 60s
Starter50,000 / month60 per rolling 60s
Professional100,000 / month60 per rolling 60s
Scale1,000,000 / month60 per rolling 60s

Current tier limits are machine-readable at GET https://api.oilpriceapi.com/v1/meta/limits (no key required); this table is rendered from it at build time. Read limits from the endpoint rather than hardcoding them.

Related Endpoints

  • Latest Prices - Current market prices
  • Commodities List - Available commodity codes
  • WebSocket Streaming - Real-time updates
Last Updated: 9/11/26, 11:08 PM
Prev
Get Latest Prices
Next
Batch Prices