OilPriceAPI Documentation
Source-timestamped oil, gas, and related energy data via REST API
Developer Quick Reference
Looking for a fast, searchable API reference? Quick Reference → - All endpoints, commodity codes, and examples in one place. Copy-paste ready.
Reviewed Product Facts
Source-timestamped oil, gas, refined-product, futures, and related energy data delivered through a normalized REST API.
- Offer: The Core commodity API includes a 7-day trial with 10,000 requests and no credit card. After the trial, the Free plan includes 50 requests per day. Dataset access and limits vary by plan, source, and account entitlement.
- Catalog: A broad catalog spanning crude oil, natural gas, refined products, futures, marine fuels, carbon markets, metals, forex, and selected energy-intelligence datasets.
- Freshness: Latest available values include source timestamps; refresh cadence varies by source, market hours, dataset, and plan.
- Authentication:
Authorization: Token YOUR_API_KEY - Environment variable:
OILPRICEAPI_KEY - First request:
GET https://api.oilpriceapi.com/v1/prices/latest?by_code=BRENT_CRUDE_USD - Keyless demo:
https://api.oilpriceapi.com/v1/demo/prices - Data rights: OilPriceAPI sells API access, normalization, monitoring, and delivery. Standard plans do not grant ownership of underlying source data or unrestricted raw-data redistribution rights. Review the Data Usage Policy before public display or redistribution.
Contract version: 2026-08-23 (canonical JSON).
What's New
- June 2026: Well Production Data — four-state launch (TX, AK, NM, ND) with US national rollup
- June 2026: AI-agent endpoints for the MCP server —
market-briefand agentsubscriptions - December 2025: 7-day free trial with 10,000 requests
- October 2025: WebSocket delivery for eligible datasets and accounts
Quick Start
Get your first API response in under 2 minutes.
Step 1: Get Your API Key
Sign up free → Dashboard → Copy API Key
Step 2: Make Your First Request
Set OILPRICEAPI_KEY in your terminal or deployment secret manager first. Run authenticated examples on your server; never embed a key in browser code. Python requires python -m pip install requests. Save the Node.js example as first-request.mjs and run it with Node.js 22 or newer. Save Go as main.go and run go run main.go.
curl --fail-with-body --max-time 10 \
"https://api.oilpriceapi.com/v1/prices/latest?by_code=BRENT_CRUDE_USD" \
-H "Authorization: Token ${OILPRICEAPI_KEY:?Set OILPRICEAPI_KEY first}"
import os
import json
import math
from datetime import datetime
import requests
response = requests.get(
"https://api.oilpriceapi.com/v1/prices/latest",
params={"by_code": "BRENT_CRUDE_USD"},
headers={"Authorization": f"Token {os.environ['OILPRICEAPI_KEY']}"},
timeout=10,
)
response.raise_for_status()
payload = response.json()
if not isinstance(payload, dict) or payload.get("status") != "success":
raise RuntimeError("The API did not return a successful price response")
data = payload.get("data")
if not isinstance(data, dict) or data.get("code") != "BRENT_CRUDE_USD":
raise RuntimeError("The API did not return the requested commodity")
price, formatted = data.get("price"), data.get("formatted")
if (type(price) not in (int, float) or not math.isfinite(price)
or not isinstance(formatted, str) or not formatted.strip()):
raise RuntimeError("The API returned a missing or invalid price")
source_as_of = data.get("as_of")
try:
observed = datetime.fromisoformat(source_as_of.replace("Z", "+00:00"))
if observed.tzinfo is None:
source_as_of = "unknown"
except (AttributeError, TypeError, ValueError):
source_as_of = "unknown"
stale = data.get("stale") if type(data.get("stale")) is bool else "unknown"
freshness = data.get("freshness")
if (data.get("data_status") == "stale"
or isinstance(freshness, dict) and freshness.get("status") == "stale"):
stale = True
print(json.dumps({
"code": data["code"], "price": price, "formatted": formatted,
"source_as_of": source_as_of, "stale": stale,
"synthetic": data.get("synthetic") if type(data.get("synthetic")) is bool else "unknown",
}))
const apiKey = process.env.OILPRICEAPI_KEY;
if (!apiKey) throw new Error("Set OILPRICEAPI_KEY first");
const response = await fetch(
"https://api.oilpriceapi.com/v1/prices/latest?by_code=BRENT_CRUDE_USD",
{
headers: { Authorization: `Token ${apiKey}` },
signal: AbortSignal.timeout(10_000),
},
);
if (!response.ok) throw new Error(`OilPriceAPI returned HTTP ${response.status}`);
const payload = await response.json();
if (payload?.status !== "success" || payload.data?.code !== "BRENT_CRUDE_USD") {
throw new Error("The API did not return the requested commodity");
}
const data = payload.data;
if (typeof data.price !== "number" || !Number.isFinite(data.price)
|| typeof data.formatted !== "string" || !data.formatted.trim()) {
throw new Error("The API returned a missing or invalid price");
}
const sourceAsOf = typeof data.as_of === "string"
&& /T.*(?:Z|[+-]\d{2}:\d{2})$/.test(data.as_of)
&& Number.isFinite(Date.parse(data.as_of)) ? data.as_of : "unknown";
let stale = typeof data.stale === "boolean" ? data.stale : "unknown";
if (data.data_status === "stale" || data.freshness?.status === "stale") stale = true;
console.log(JSON.stringify({
code: data.code, price: data.price, formatted: data.formatted,
source_as_of: sourceAsOf, stale,
synthetic: typeof data.synthetic === "boolean" ? data.synthetic : "unknown",
}));
package main
import (
"encoding/json"
"log"
"net/http"
"os"
"strings"
"time"
)
func main() {
key := os.Getenv("OILPRICEAPI_KEY")
if key == "" { log.Fatal("Set OILPRICEAPI_KEY first") }
req, err := http.NewRequest("GET",
"https://api.oilpriceapi.com/v1/prices/latest?by_code=BRENT_CRUDE_USD", nil)
if err != nil { log.Fatal(err) }
req.Header.Set("Authorization", "Token " + key)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil { log.Fatal(err) }
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK { log.Fatalf("OilPriceAPI returned HTTP %d", resp.StatusCode) }
var payload struct {
Status string `json:"status"`
Data *struct {
Code string `json:"code"`
Price *float64 `json:"price"`
Formatted *string `json:"formatted"`
AsOf *string `json:"as_of"`
Stale *bool `json:"stale"`
Synthetic *bool `json:"synthetic"`
DataStatus string `json:"data_status"`
Freshness struct { Status string `json:"status"` } `json:"freshness"`
} `json:"data"`
}
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil { log.Fatal(err) }
data := payload.Data
if payload.Status != "success" || data == nil || data.Code != "BRENT_CRUDE_USD" {
log.Fatal("The API did not return the requested commodity")
}
if data.Price == nil || data.Formatted == nil || strings.TrimSpace(*data.Formatted) == "" {
log.Fatal("The API returned a missing or invalid price")
}
sourceAsOf := "unknown"
if data.AsOf != nil {
if _, err := time.Parse(time.RFC3339, *data.AsOf); err == nil { sourceAsOf = *data.AsOf }
}
var stale, synthetic any = "unknown", "unknown"
if data.Stale != nil { stale = *data.Stale }
if data.Synthetic != nil { synthetic = *data.Synthetic }
if data.DataStatus == "stale" || data.Freshness.Status == "stale" { stale = true }
if err := json.NewEncoder(os.Stdout).Encode(map[string]any{
"code": data.Code, "price": *data.Price, "formatted": *data.Formatted,
"source_as_of": sourceAsOf, "stale": stale, "synthetic": synthetic,
}); err != nil { log.Fatal(err) }
}
Step 3: Response Shape
Values and source labels below are illustrative. as_of is the original source observation time; collected_at is ingestion time. A recent created_at does not prove the source observation is recent. synthetic: true identifies a carried-forward or heartbeat value; retain that warning and stale when present.
{
"status": "success",
"data": {
"price": 74.52,
"formatted": "$74.52",
"currency": "USD",
"code": "BRENT_CRUDE_USD",
"created_at": "2026-07-18T15:30:00.000Z",
"as_of": "2026-07-17T16:00:00.000Z",
"collected_at": "2026-07-18T15:30:00.000Z",
"stale": true,
"synthetic": true,
"type": "spot_price",
"source": "example_source",
"metadata": {
"source": "example_source"
}
}
}
The cURL example prints the raw API response above. Python, Node.js, and Go validate the requested code and price fields, then print a summary with source_as_of, stale, and synthetic. Missing or invalid source time and absent freshness flags are labelled "unknown", never inferred from collection time. Any explicit stale signal wins. These summaries are not the API schema. They demonstrate inspection; they do not certify a price as current. Apply your source schedule and age tolerance before using the observation, and retain the raw response's currency, unit, source, and provenance when storing prices.
For a single by_code, read the price from data. Multiple codes return data.prices[]; find each requested code in that array. The demo has its own shape and uses updated_at. See latest-price response fields.
Build with an AI Agent
Start with the agent integration guide, or give your agent the plain Markdown quickstart. Use OpenAPI YAML for supported operations and llms.txt for documentation discovery.
Common Commodity Codes
| Code | Description | Category |
|---|---|---|
WTI_USD | West Texas Intermediate Crude Oil | Crude Oil |
BRENT_CRUDE_USD | Brent Crude Oil | Crude Oil |
NATURAL_GAS_USD | Henry Hub Natural Gas | Natural Gas |
DIESEL_USD | Ultra Low Sulfur Diesel | Refined Products |
HEATING_OIL_USD | Heating Oil No. 2 | Refined Products |
JET_FUEL_USD | Jet Fuel (Kerosene) | Refined Products |
GASOLINE_USD | RBOB Gasoline | Refined Products |
COAL_USD | Thermal Coal (Newcastle) | Coal |
First Call Troubleshooting
| Error | Cause | Solution |
|---|---|---|
401 Unauthorized | Invalid or missing API key | Check header format: Authorization: Token YOUR_KEY (not Bearer) |
invalid_code (400) | Unknown commodity code in by_code | Use codes from the table above. Codes are case-insensitive. |
429 Too Many Requests | Rate limit exceeded | Read the response limit headers, implement backoff, and verify the current account limit. |
TRIAL_EXPIRED | 7-day trial ended | Continue within the Free plan limit or review current plans →. |
| Connection timeout | Network issue | Retry with exponential backoff. Check API status |
Base URL
https://api.oilpriceapi.com/v1
Authentication
Authenticated endpoints require an API key in the Authorization header. The keyless demo is public:
Authorization: Token YOUR_API_KEY
See the Authentication Guide for security best practices and code examples.
Core Endpoints
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | /prices/latest | Latest commodity prices | Yes |
| GET | /prices/past_day | Hourly prices (24h) | Yes |
| GET | /prices/past_week | Daily prices (7d) | Yes |
| GET | /prices/past_month | Daily prices (30d) | Yes |
| GET | /prices/historical | Custom date range | Yes (Paid) |
| GET | /commodities | List all commodities | Yes |
Documentation
- Quick Reference - Fast, searchable cheat sheet with all codes and endpoints
- API Reference - Complete endpoint documentation
- Swagger UI - Interactive API explorer
- Authentication Guide - Security and best practices
- Error Codes - Error handling reference
- Rate Limiting - Usage limits and optimization
- Production Checklist - Go-live preparation
SDKs & Direct REST Guides
- Official Python SDK guide
- Official Node.js SDK guide
- Official Go SDK guide
- Official PHP SDK guide
- Ruby direct REST guide (no official gem)
- C# direct REST guide (no official NuGet package)
- Java direct REST guide
- R direct REST guide
- Rust direct REST guide
Integrations
Support
- Email: support@oilpriceapi.com
- API Status: api.oilpriceapi.com/v1/status