All notable changes to the OilPriceAPI Python SDK will be documented in this file.
- Validate every customer-readable member in the exact built source distribution, including root release/configuration files and future nested package data, while explicitly excluding intentional test/tooling fixtures.
- Remove the unsupported universal-entitlement wording from the packaged environment example and reject never-existent promises that attribution headers change entitlements in authored and distributed release notes.
- Removed a nonexistent request-limit bonus claim from sync and async usage-attribution header comments.
- Added red-first recursive authored and installed-wheel claim coverage so telemetry or application metadata cannot be presented as changing account entitlements.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
- Route Brent, WTI, gasoil, and EU carbon futures through the API's instrument-generic paths in sync and async clients. Existing venue-slug and contract-code inputs remain compatible and normalize to those same paths.
- Document a coverage-gated permit-to-production workflow and package discovery keywords for well permits, drilling data, and well production.
- Accept live well-permit filters without a legacy free-form query and unwrap
the production
{ well_permits, meta }search response in sync and async clients while retaining positional-query compatibility. - Require the PyPI publisher to verify the complete checksummed artifact set, share one package-version parser, scan both workflow filename extensions, and allow bounded public-index propagation before release completion.
- Reject common fixed request and API-call rate spellings, including prefix, suffix, and hyphenated daily/hourly/minute forms, and direct examples to the reviewed live product facts.
- Match hyphenated free-tier wording and universal catalog claims in every readable wheel surface, and replace the remaining packaged docstrings with current-account and runtime-response terminology.
- Remove stale fixed plan-price, monthly allowance, cadence, uptime, and generic real-time claims from documentation and packaged docstrings.
- Recursively validate authored docs and package source, then scan the exact installed wheel and PyPI metadata during the release smoke test.
- Read release metadata without importing the uninstalled source package, so the trusted publisher can validate the exact wheel from a build-only clean environment before PyPI upload.
- Add sync and async
client.commodities.search(...), backed by the current API catalog rather than a bundled commodity-code list. - Expose bounded, credential-redacted
suggestionsandinvalid_codesfrom nested invalid-code error responses.
- Date-bearing resources now reject malformed or impossible
YYYY-MM-DDstrings locally while leaving well-formed range semantics to the API. - Historical DataFrame helpers now accept a
per_pagevalue from 1 to 1000 and fetch all pages automatically. Theclient.prices.to_dataframe(...)convenience path forwards the same option for date-range queries.
- Stop retrying exhausted daily, monthly, and trial quota responses. Sync and async clients now make one request at a durable quota wall while preserving bounded retry behavior for recoverable hourly and ambiguous 429 responses.
- Replace the demo synthetic's fixed catalogue-size assertion with an integrity contract for the original core codes and every usable returned row. Request, transport, and operating-system failures now fail the monitor instead of being converted to skips.
- Preserve each API record's currency and unit in current and historical DataFrames instead of labeling a missing currency as USD.
- Remove exact duplicate records introduced by overlapping page boundaries, stop safely on empty pages with stale continuation metadata, and return a stable schema for empty historical DataFrames.
- Replaced the PyPI storefront with reviewed source-timestamped wording and removed unsupported fixed catalog, traffic, cadence, and entitlement claims.
- Made the canonical first-request snippet fail closed unless symbol, numeric value, currency, unit, source, and an exact API timestamp field are present.
- Added a storefront claim guard and corrected the history snippet's declared endpoint to match its executable request path.
- Well Production Resource (beta):
client.well_production(and async mirror) covering/v1/well-production*—summary(),states(),state(),well(),top_producers(),cycle_time(),cycle_time_cohorts(). Per-well data is beta and limited to states with collected regulatory data; endpoints are gated on the Drilling Intelligence feature (403ENTERPRISE_REQUIRED). Closes #50.
- Removed a committed API-key fallback from
tests/sdk_audit_test.py; the audit script now readsOILPRICEAPI_KEY/OILPRICEAPI_TEST_KEYfrom the environment only and skips cleanly when unset.
- Loosen
sourcetyping and align examples with the API's masked source labels: the responsesourcenow returnsmarket_reportingfor non-government series (government labels likeEIA/opec.orgare unchanged). Modelsourcefields remain a freestr(no venue enum); test fixtures no longer use venue names such asICE. See oilpriceapi-api#4175.
- docs: registry storefront README — hero, "What can you get?" commodity table, and cross-SDK toolbox table so the PyPI page matches the other OilPriceAPI SDKs. No code changes.
- Analysis Resource (Technical Indicators):
client.analysiswithwith_indicators(df, indicators=[...])DataFrame helper and direct methodssma(),ema(),rsi(),macd(),bollinger_bands(),atr(). Pure pandas/numpy implementation, no new dependencies. Closes #3.
- Commodities Resource:
client.commodities.list(),get(code),categories()for commodity catalog discovery - Futures Resource:
client.futures.latest(),historical(),ohlc(),intraday(),spreads(),curve(),continuous()for futures contract data - Storage Resource:
client.storage.all(),cushing(),spr(),regional(),history()for oil inventory levels - Rig Counts Resource:
client.rig_counts.latest(),current(),historical(),trends(),summary()for Baker Hughes rig count data - Bunker Fuels Resource:
client.bunker_fuels.all(),port(),compare(),spreads(),historical(),export()for marine fuel prices - Analytics Resource:
client.analytics.performance(),statistics(),correlation(),trend(),spread(),forecast()for price analytics - Forecasts Resource:
client.forecasts.monthly(),accuracy(),archive(),get()for EIA monthly price forecasts - Data Quality Resource:
client.data_quality.summary(),reports(),report()for data quality monitoring - Drilling Intelligence Resource:
client.drilling.latest(),summary(),trends(),frac_spreads(),well_permits(),duc_wells(),completions(),wells_drilled(),basin()for drilling activity data - Energy Intelligence Resource:
client.eiwith 7 sub-resources:rig_counts,oil_inventories,opec_production,drilling_productivity,forecasts,well_permits,frac_focusfor comprehensive EIA data - Webhooks Resource:
client.webhooks.create(),list(),get(),update(),delete(),test(),events()for webhook management - Data Sources Resource:
client.data_sources.list(),get(),create(),update(),delete(),test(),logs(),health(),rotate_credentials()for data connector management - Enhanced Alerts: Added
test(),triggers(),analytics_history()methods to existing alerts resource - Data Connector Support:
client.get_data_connector_prices()for BYOS (Bring Your Own Subscription) prices - Telemetry Headers:
app_urlandapp_nameparameters for API usage attribution
- Diesel validation: Empty string state codes now properly rejected with ValidationError
- 84 new unit tests added (222 total, 0 failures)
- Test coverage improved from ~40% to 60%
- New test files for all 13 resource modules
None - All new resources are additive. Existing code continues to work unchanged.
-
CRITICAL: Historical Data Returns Wrong Commodity: Fixed issue where all historical queries returned BRENT_CRUDE_USD regardless of requested commodity
- Root cause: SDK was sending
commodityparameter but API expectsby_codeparameter - Impact: ALL historical queries since v1.4.0 returned incorrect data
- Solution: Changed parameter name from
commoditytoby_codein historical resource - Reported by: Idan (idan@comity.ai)
- Root cause: SDK was sending
-
Date Range Parameters Ignored: Fixed issue where start_date and end_date parameters were completely ignored
- Root cause: API endpoints were hardcoded to return last week/month/year from current date
- Impact: Requesting specific date ranges (e.g., Jan 2024) would return current period instead
- Solution: API now respects start_date and end_date parameters across all historical endpoints
- This fix was applied to the backend API simultaneously
- Strict Commodity Validation: API now validates commodity codes and returns clear error messages for invalid codes
- Before: Silently accepted invalid codes like "oijfoijofwijewef" and returned BRENT data
- After: Returns 400 Bad Request with list of valid codes
- Error includes link to
/v1/prices/metricsfor full list of valid commodity codes
None - This is a critical bug fix. Existing code will work correctly after update.
CRITICAL - All users of client.historical.get() should upgrade immediately. Previous versions return completely wrong data.
- Historical Queries Timeout Issue: Fixed 100% timeout rate on historical data requests
- Root cause: SDK was using hardcoded
/v1/prices/past_yearendpoint for all date ranges - Solution: Implemented intelligent endpoint selection based on date range
- 1 day range →
/v1/prices/past_dayendpoint - 7 day range →
/v1/prices/past_weekendpoint - 30 day range →
/v1/prices/past_monthendpoint - 365 day range →
/v1/prices/past_yearendpoint
- 1 day range →
- Performance improvement: 7x faster for 1 week queries, 3x faster for 1 month queries
- Root cause: SDK was using hardcoded
- Dynamic Timeout Management: Automatic timeout adjustment based on query size
- 1 week queries: 30 seconds (previously 30s, but now uses optimal endpoint)
- 1 month queries: 60 seconds
- 1 year queries: 120 seconds (up from 30s - fixes timeout issue)
- Custom timeout override:
historical.get(..., timeout=180)for very large queries
- Per-Request Timeout Override: Added
timeoutparameter toclient.request()method- Allows fine-grained timeout control for specific requests
- Historical resource automatically uses appropriate timeouts
- 1 week historical queries: 67s → ~10s (7x faster via
/past_weekendpoint) - 1 month historical queries: 67s → ~20s (3x faster via
/past_monthendpoint) - 1 year historical queries: Timeout (30s) → Success (67-85s with 120s timeout)
- Added 9 new tests for endpoint selection and timeout handling
- All 20 existing tests pass with new changes
- Test coverage for
historical.py: 88.68% (up from ~54%)
- Updated
historical.get()docstring with timeout parameter examples - Added clear examples for custom timeout usage
None - This is a backwards-compatible bug fix. Existing code will continue to work and will automatically benefit from performance improvements.
- Price Alerts: New
client.alertsresource for automated price monitoring - Alert CRUD Operations: Complete create, read, update, delete operations
- Webhook Notifications: HTTPS webhook support for alert triggers
- Alert Operators: 5 comparison operators (greater_than, less_than, equals, greater_than_or_equal, less_than_or_equal)
- Cooldown Periods: Rate limiting for alert triggers (0-1440 minutes)
- Webhook Testing: Test webhook endpoints before creating alerts
- DataFrame Support:
alerts.to_dataframe()- Convert alerts to pandas DataFrames - New Pydantic models:
PriceAlert- Alert configuration and statusWebhookTestResponse- Webhook test results
- Comprehensive Validation: Input validation for all alert parameters
- Type Safety: Full Pydantic models with datetime handling
- Error Handling: Specific ValidationError exceptions with field details
- Pandas Integration: Built-in DataFrame conversion for analysis
- Documentation: Complete docstrings with examples
Now supports 12 endpoints (up from 7):
GET /v1/prices/latest- Get latest commodity pricesGET /v1/prices- Get historical commodity pricesGET /v1/commodities- Get all commodities metadataGET /v1/commodities/categories- Get commodity categoriesGET /v1/commodities/{code}- Get specific commodity detailsGET /v1/diesel-prices- Get state average diesel pricesPOST /v1/diesel-prices/stations- Get nearby diesel stationsGET /v1/alerts- List all price alerts (NEW)GET /v1/alerts/{id}- Get specific alert (NEW)POST /v1/alerts- Create price alert (NEW)PATCH /v1/alerts/{id}- Update price alert (NEW)DELETE /v1/alerts/{id}- Delete price alert (NEW)
- Added comprehensive test suite for alerts resource (22 test cases)
- Tests cover all CRUD operations, validation, webhook testing, and DataFrame operations
- 82% coverage of alerts functionality
None - This is a backwards-compatible feature addition.
from oilpriceapi import OilPriceAPI
client = OilPriceAPI()
# Create a price alert
alert = client.alerts.create(
name="Brent High Alert",
commodity_code="BRENT_CRUDE_USD",
condition_operator="greater_than",
condition_value=85.00,
webhook_url="https://your-server.com/webhook",
cooldown_minutes=60
)
# List all alerts
alerts = client.alerts.list()
for alert in alerts:
print(f"{alert.name}: {alert.trigger_count} triggers")
# Update alert
client.alerts.update(alert.id, condition_value=90.00)
# Test webhook
test_result = client.alerts.test_webhook("https://your-server.com/webhook")
print(f"Webhook OK: {test_result.success}")
# Get as DataFrame
df = client.alerts.to_dataframe()- Diesel Prices Support: New
client.dieselresource for diesel price data - State Average Diesel Prices:
diesel.get_price(state)- Get EIA state-level diesel averages (free tier) - Station-Level Diesel Pricing:
diesel.get_stations(lat, lng, radius)- Get nearby diesel stations with current prices from Google Maps (paid tiers) - Diesel DataFrame Support:
diesel.to_dataframe()- Convert diesel data to pandas DataFrames - New Pydantic models:
DieselPrice- State average diesel price dataDieselStation- Individual diesel station with pricingDieselStationsResponse- Response from stations endpointDieselRegionalAverage- Regional average for comparisonDieselSearchArea- Search area detailsDieselStationsMetadata- Query metadata
- Input Validation: Comprehensive validation for coordinates, state codes, and radius
- Error Handling: Specific errors for tier restrictions (403) and rate limits (429)
- Type Safety: Full Pydantic models for all diesel operations
- Pandas Integration: Built-in DataFrame conversion for analysis
- Documentation: Complete docstrings with examples
Now supports 7 endpoints (up from 5):
GET /v1/prices/latest- Get latest commodity pricesGET /v1/prices- Get historical commodity pricesGET /v1/commodities- Get all commodities metadataGET /v1/commodities/categories- Get commodity categoriesGET /v1/commodities/{code}- Get specific commodity detailsGET /v1/diesel-prices- Get state average diesel prices (NEW)POST /v1/diesel-prices/stations- Get nearby diesel stations (NEW)
- Added comprehensive test suite for diesel resource (18 test cases)
- Tests cover input validation, error handling, and DataFrame operations
- 100% coverage of diesel functionality
None - This is a backwards-compatible feature addition.
from oilpriceapi import OilPriceAPI
client = OilPriceAPI()
# State average (free tier)
ca_price = client.diesel.get_price("CA")
print(f"California diesel: ${ca_price.price:.2f}/gallon")
# Nearby stations (paid tiers)
result = client.diesel.get_stations(lat=37.7749, lng=-122.4194)
cheapest = min(result.stations, key=lambda s: s.diesel_price)
print(f"Cheapest: {cheapest.name} at {cheapest.formatted_price}")
# DataFrame analysis
df = client.diesel.to_dataframe(states=["CA", "TX", "NY", "FL"])
print(df[["state", "price", "updated_at"]])- 🎉 Initial release of OilPriceAPI Python SDK
- ✅ Synchronous client (
OilPriceAPI) - ✅ Asynchronous client (
AsyncOilPriceAPI) - ✅ Type-safe models with Pydantic
- ✅ Current price operations (
client.prices.get()) - ✅ Historical data operations (
client.historical.get()) - ✅ Pandas DataFrame integration (
to_dataframe()) - ✅ Visualization module with Tufte-style charts
- ✅ Automatic retry logic with exponential backoff
- ✅ Rate limit handling
- ✅ Comprehensive error handling
- ✅ Context manager support (
withstatements) - ✅ Environment variable configuration
- ✅ Full type hints for IDE autocomplete
- ✅ Documentation and examples
- Current Prices: Get latest commodity prices
- Historical Data: Fetch past prices with flexible date ranges
- Multi-commodity: Support for Brent, WTI, Natural Gas, and more
- Pagination: Automatic handling of large datasets
- Data Export: Convert to pandas DataFrames for analysis
- Async Support: High-performance async/await operations
- Visualization: Built-in charting with matplotlib
- Type Safety: Full Pydantic validation
- Environment variable-based API key management
- No hardcoded credentials
- HTTPS-only communication
- Safe error messages that don't leak secrets
- Comprehensive README with examples
- API reference documentation
- Security policy (SECURITY.md)
- Contributing guidelines (CONTRIBUTING.md)
- Example scripts and notebooks
- Python 3.8+
- Python 3.9
- Python 3.10
- Python 3.11
- Python 3.12
# From PyPI
pip install --upgrade oilpriceapi
# From source
pip install -e ".[dev]"None - this is the initial release.
None.
N/A for initial release.