All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
Four methods called routes the API has never served, so every call returned HTTP 404 (#125). They now reject immediately with OilPriceAPIError code ENDPOINT_NOT_AVAILABLE, name the supported alternative, and make no request. They are deprecated and will be removed in the next major.
client.drilling.trends(): no trends endpoint exists. Usesummary(), orcompletions()/wellsDrilled()/ducWells()for basin-level series.client.drilling.basin(name): no per-basin endpoint exists. Read theby_basinmaps fromcompletions(),wellsDrilled(),ducWells()orfracSpreads().client.futures.spreads(contract1, contract2): no arbitrary two-contract spread endpoint exists. Useclient.futures.family(slug).spreads(), e.g.client.futures.brent().spreads().client.futures.continuous(contract, months): no per-contract continuous endpoint exists. UsecontinuousFrontMonth().
client.futures.continuousFrontMonth("brent" | "wti")forGET /v1/futures/continuous/{family}, returningContinuousFrontMonth.tests/api-path-contract.test.ts, which fails CI when any SDK path is missing from a snapshot of the API's routes. Refresh the snapshot withscripts/refresh-api-paths.mjs.
- Dev-only lockfile updates: fast-uri 3.1.8 (GHSA-hrr3-gc8f-f4qj) and markdown-it 14.3.2 (GHSA-253c-mchw-3w2r).
A major release: several resources were typed and called in ways production never supported. The changes below are breaking at compile time or runtime, and in nearly every case the old call could not work correctly against the live API.
Spreads (client.spreads) (#112)
- Removed
get(type),historical(type, options)andall(type). They could not send the parameters the routes require; use the named methods. basis(pair)andcurveStructure(commodity)now require their argument.crack({ type, crude }),margin({ index })andphysicalPremium({ commodity })take an options object and returnCrackSpread,RefineryMarginandPhysicalPremiumwith the field names the API sends (spread_type,margin_usd_bbl,premium_pct).SpreadValue,HistoricalSpreadValue,HistoricalSpreadOptionsandSpreadTypeare deprecated.
Indicators (client.indicators) (#112)
- Removed
get(type),congressionalTrades()andCongressionalTradeIndicator. The route has never returned data. priceContext(code, { relatedSpreads })andannotations(code)now requirecode.annotationsreturns aMarketAnnotationsobject instead of an array.cftcPositioning({ commodity })returns oneCftcPositioningobject; the list iscftcPositioningAll().fuelSwitching()andstorageAnalytics()returnFuelSwitchingandStorageAnalytics.- Deprecated aliases:
FuelSwitchingIndicator,PriceContextIndicator,StorageAnalyticsIndicator,AnnotationIndicator(now a single annotation) andCFTCPositioningIndicator.IndicatorTypeno longer includes"congressional-trades".
Rig counts (client.rigCounts) (#108)
latest()returnsRigCountObservation, with the value incount.total,oil,gas,misc,timestampandchangeare gone because no route sends them; useclient.ei.rigCountsfor the oil/gas split.RigCountDatais a deprecated alias.current()returnsCurrentRigCounts.historical()returns the page envelopeRigCountsPage. It previously returnedundefined.trends()rejects periods the route does not honour (week,month,quarter,year) withValidationError.
Energy Intelligence (client.ei) (#104, #105)
- Rig-count reports:
list()returnsRigCountReportSummary[];latest()andget(id)returnRigCountReportwith totals underus_total.RigCountRecordis a deprecated alias. - The six
by*methods onwellPermitsandfracFocusnow require their filter, throwValidationErrorbefore sending when it is missing, and return the records together with paginationmetainstead of a bare array.
Subscriptions (#78)
subscriptions.list()throwsunexpected_response_shapeinstead of resolving[]when the response has nosubscriptionsarray, so[]now only ever means the API sent an empty list.create()likewise throws on a body it cannot map.
Published types (#94)
- Types describe the payloads production returns.
CategoriesResponsechanged shape, so code readingcategories.oilno longer compiles (it could not work at runtime).Commodity.categoryis optional.
Errors (#111, #117)
- For
{ status: "fail", data: { ... } }responses,error.messagenow carries the API's reason, and a snake-casedata.error(VALIDATION_ERROR,invalid_code,no_price_data) becomeserror.code. Code that branched on"HTTP_ERROR"for these responses should branch on the specific code.error.codeis no longerundefinedwhen the body carries none.
Base URL (#89)
- A
baseUrlcontaining a query string or fragment now throws at construction, and the base path is pinned.
Unmappable responses
- Across rig counts, spreads, indicators, Energy Intelligence and subscriptions, a 200 whose body cannot be mapped raises
OilPriceAPIErrorwithcode: "unexpected_response_shape"instead of returning an object with missing fields.
- Spreads:
crackHistorical,crackAll,gasoilCrack,basisHistorical,basisAll,curveStructureAll,marginHistorical,marginAll,physicalPremiumHistoricalandphysicalPremiumAll(#112). - Indicators:
fuelSwitchingHistorical,storageAnalyticsAll,annotationsBatch(up toANNOTATIONS_BATCH_MAX_CODES, 20 codes),cftcPositioningHistoricalandcftcPositioningAll(#112). - Subscriptions:
get,update,pauseandresume(#78). - Fuel surcharge: typed LTL and parcel clients (#79).
- Rig counts:
latest({ code }),historical({ period, page, perPage, code })andtrends({ period, region })(#108).
- The request timeout stays armed until the response body has been read (#81).
- Pagination no longer stops at the server's 500-row page cap (#90).
- Caller-supplied ids are encoded into a single path segment (#92).
- The streaming client no longer terminates its host process on a socket error, ends a permanently rejected stream, and bounds setup (#91, #84).
- CommonJS consumers get
.d.ctsdeclarations, and@types/wsand@types/nodeare runtime dependencies (#93). - Energy Intelligence methods no longer return
undefinedafter double unwrapping (#83).
- Raw paths can no longer change the authenticated API origin (#87). A bare
relative path was the worst form:
v1/pricesproduced the hostapi.oilpriceapi.comv1— it looks like an ordinary path and silently became a foreign hostname carrying the API key. Userinfo append (@fixture.invalid), host-suffix append (.fixture.invalid->api.oilpriceapi.com.fixture.invalid), a bare port (:8443) and scheme prefixes all reached hosts that were not ours. 14 attack forms and 3 legitimate forms are asserted against the real outboundfetch.
- Breaking: non-idempotent writes are no longer replayed (#88). POST was retried 4x on timeout, 4x on 503 and 4x on a malformed 200; PATCH 4x on 502.
- Breaking:
retries: -1now throws at construction instead of failing later with "Unknown error occurred".
- Durable quota exhaustion is no longer retried — it was retried 4x, sleeping
3 x 3,600,000 ms. Detection reads
X-RateLimit-Stateand the counter names, verified against the API'sbase_controller.rb, not guessed from prose. Retry-After: 86400no longer sleeps 86,400,000 ms, and a bodyretry_after: -30no longer sleeps -30,000 ms.retryDelay: 0is honoured instead of silently becoming 1000 ms.
- Scan every customer-readable file in the exact packed npm distribution, regardless of filename suffix, so future text, Markdown, source-map, or extensionless package data cannot bypass the storefront claim contract. Binary package data remains excluded from text parsing.
- Remove the nonexistent telemetry request-bonus claim from authored and generated package surfaces. The recursive storefront guard now rejects equivalent telemetry or app-metadata quota rewards in both source and the exact packed npm artifact.
- Remove the stale monthly quota assumption from customer recovery copy and reject fixed daily, weekly, monthly, or yearly quota-window claims even when they do not contain a numeric allowance. Quota recovery now follows the live API response and reviewed product facts.
- Resolve npm publication state from typed registry responses so only an exact HTTP 404 permits first publication, while mismatched metadata, malformed responses, server errors, and network failures stop the release.
- Verify both the exact public version and the
latesttag against the checksummed tarball before completing the release.
- Document a coverage-gated permit-to-production flow using live permit search results and per-well monthly production history.
- Add well-permit, drilling-data, and oil-well-production discovery keywords.
- Route futures contract codes and named helpers through instrument-generic Brent, WTI, Gasoil, and EU-carbon paths while retaining explicit legacy slugs as backward-compatible inputs.
- Unwrap the production
{ well_permits, meta }search envelope through the newsearchLatest()method while preserving the existingsearch()return type.
- Remove stale plan-price, quota-exemption, cadence, cost-comparison, and generic real-time claims from generated docs and published package comments.
- Discover authored docs and package source recursively, then validate the exact packed npm artifact so a generated declaration cannot bypass the reviewed product-claim contract.
- Allow clients without credentials to call the public demo price and
commodity methods without sending an
Authorizationheader. - Export normalized authentication, authorization, validation, rate-limit, quota, server, and timeout error classes with stable recovery metadata.
- Fail authenticated HTTP and streaming calls locally with
MISSING_API_KEYinstead of constructing an invalid request. - Validate the dynamic demo catalogue by contract and make production 429s fail the live release gate rather than silently skipping the check.
- Update runtime, build, lint, type, and GitHub Actions dependencies and resolve all known npm audit findings at release time.
- Replaced the npm 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 the source-context response fields to the public
Pricetype and a CI storefront claim guard.
- 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). TheFuturesPrice.sourcefield remains a freestring(no venue enum); doc-comment and test fixture examples 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 npm page matches the other OilPriceAPI SDKs. No code changes.
First stable release. The public API surface is now covered by semantic versioning: breaking changes will only ship in major versions.
- Bunker fuels response types corrected to match the live API (#29):
bunkerFuels.port():pricesis an array of per-grade entries ({ grade, grade_name, price, currency, unit, change_24h, change_pct_24h, last_updated, ... }), not a{ VLSFO: number }keyed object.portis an info object ({ code, name, country, ... }), not a string. Response also includesspreadsandmetadatablocks.bunkerFuels.all()returns{ ports, metadata }with port data keyed by port code (previously typed as a flat array; at runtime it returnedundefinedbecause the declared shape never matched the API).bunkerFuels.compare()returns{ comparison, spreads, metadata }with per-port data keyed by port code (previously typed as{ fuel_type, ports: [...] }).bunkerFuels.spreads()returns{ from_port, to_port, fuel_grade, spreads, metadata }.bunkerFuels.historical()returns{ port, historical_data, period, metadata }(previously typed as a flat array; at runtime it returnedundefined).bunkerFuels.export()is typed asBunkerExportRow[](JSON format).- New exported types:
BunkerPortInfo,BunkerSpreadValue,BunkerResponseMetadata,PortPricesEntry,AllBunkerPrices,PortToPortSpreadDetail,HistoricalBunkerData,BunkerExportRow.BunkerFuelPrice,PortBunkerPrices,PortPriceComparison,BunkerFuelSpreads, andHistoricalBunkerPricehave new shapes.
- README bunker examples now use valid 3-letter port codes (
SIN, notSGSIN— the route only accepts[A-Z]{3}) and the correctcompare(["SIN", "RTM"])signature.
- Commodities Resource:
client.commodities.list(),get(),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()for oil inventory levels - Rig Counts Resource:
client.rigCounts.current(),historical(),latest(),summary()for Baker Hughes rig count data - Bunker Fuels Resource:
client.bunkerFuels.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.dataQuality.summary(),reports(),report()for data quality monitoring - Drilling Intelligence Resource:
client.drilling.latest(),summary(),trends(),fracSpreads(),wellPermits(),ducWells(),completions(),wellsDrilled(),basin()for drilling activity data - Energy Intelligence Resource:
client.eiwith 7 sub-resources:rigCounts,oilInventories,opecProduction,drillingProductivity,forecasts,wellPermits,fracFocusfor comprehensive EIA data - Webhooks Resource:
client.webhooks.create(),list(),get(),update(),delete(),test(),events()for webhook management - Data Sources Resource:
client.dataSources.list(),get(),create(),update(),delete(),test(),logs(),health()for data connector management - Enhanced Alerts: Added
test(),triggers(),analyticsHistory()methods to existing alerts resource - Data Connector Support:
client.getDataConnectorPrices()for BYOS (Bring Your Own Subscription) prices - Telemetry Headers:
appUrlandappNameoptions for API usage attribution
- 70 new unit tests added (185 total, 0 failures)
- 13 new test files covering all resource modules
- All tests pass with TypeScript strict mode
None - All new resources are additive. Existing code continues to work unchanged.
- PERFORMANCE: Added
intervalparameter togetHistoricalPrices()for aggregated queries'raw'- Individual price points (default, can be slow for year-long queries)'hourly'- Hourly averages'daily'- Daily averages (recommended for year-long queries - 365 points vs 600k+)'weekly'- Weekly averages (52 points per year)'monthly'- Monthly averages (12 points per year)
- PERFORMANCE: Added
perPageparameter for pagination control (default: 100, max: 1000) - PERFORMANCE: Added
pageparameter for pagination navigation - New TypeScript type:
AggregationInterval
- Year-long queries improved from 74+ seconds to <1 second when using
interval: 'daily' - Example:
getHistoricalPrices({ period: 'past_year', commodity: 'BRENT_CRUDE_USD', interval: 'daily' })
- Added 7 new tests for interval and pagination parameters
- All 118 tests passing
None - This is a backwards-compatible feature addition. Existing code continues to work.
- CRITICAL: Fixed historical date range queries returning incorrect dates
- Changed
getHistoricalPrices()to use/v1/prices/past_yearendpoint instead of/v1/prices - The
/v1/pricesendpoint was not correctly handlingstart_date/end_dateparameters - This was the same bug that affected the Python SDK (fixed in v1.4.4)
- Users requesting data for specific date ranges now receive correct results
- Changed
- Added comprehensive test suite for historical price queries (22 new tests)
- Added error handling test suite (31 new tests)
- Test coverage now at 95%+ for all source files
None - This is a bug fix that corrects behavior to match documentation.
- Centralized version management in
src/version.ts - Export
SDK_VERSIONandSDK_NAMEconstants for tracking - User-Agent header:
oilpriceapi-node/{version} node/{node_version} X-Api-ClientandX-Client-Versionheaders for SDK tracking
- Added integration tests for User-Agent header verification (11 tests)
- Minor improvements to diesel and alerts resources
- Price Alerts: New
client.alertsresource for automated price monitoring with webhook notifications - Alert Management: Full CRUD operations for price alerts
alerts.list()- Get all configured alertsalerts.get(id)- Get specific alert by IDalerts.create(params)- Create new price alertalerts.update(id, params)- Update existing alertalerts.delete(id)- Delete an alertalerts.testWebhook(url)- Test webhook endpoint
- Alert Operators: 5 comparison operators for flexible conditions
greater_than- Trigger when price exceeds thresholdless_than- Trigger when price falls below thresholdequals- Trigger when price matches threshold exactlygreater_than_or_equal- Trigger at or above thresholdless_than_or_equal- Trigger at or below threshold
- Webhook Integration: HTTPS webhook notifications when alerts trigger
- Cooldown Periods: Configurable cooldown (0-1440 minutes) to prevent alert spam
- New TypeScript interfaces:
PriceAlert,CreateAlertParams,UpdateAlertParams,AlertOperator,WebhookTestResponse - Comprehensive input validation for all alert parameters
- Detailed error handling with clear validation messages
- Added complete Price Alerts section to README with examples
- Added CRUD operation examples for alerts
- Added webhook payload documentation
- Updated Quick Examples section with alerts example
- Updated feature list to highlight price alerts
- Added API reference for alert limits and constraints
- Added comprehensive test suite for alerts resource (24 test cases)
- Tests cover all CRUD operations and validation scenarios
- 100% coverage of alerts functionality
- Tests for all 5 alert operators
- Validation tests for name, commodity code, operator, value, webhook URL, and cooldown
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 alert (NEW)DELETE /v1/alerts/{id}- Delete alert (NEW)
None - This is a backwards-compatible feature addition.
- Diesel Prices Support: New
client.dieselresource for diesel price data - State Average Diesel Prices:
diesel.getPrice(state)- Get EIA state-level diesel averages (free tier) - Station-Level Diesel Pricing:
diesel.getStations(options)- Get nearby diesel stations with current prices from Google Maps (paid tiers) - New TypeScript interfaces:
DieselPrice,DieselStation,DieselStationsResponse,GetDieselStationsOptions - Comprehensive input validation for coordinates, state codes, and radius
- Detailed error handling for tier restrictions (403) and rate limits (429)
- Added diesel prices usage examples to README
- Added API reference section for
client.dieselresource - Added complete type definitions for all diesel-related interfaces
- Updated Quick Examples section with diesel examples
- Updated feature list to highlight diesel prices support
- Added comprehensive test suite for diesel resource (15 test cases)
- Tests cover input validation, error handling, and API responses
- 100% coverage of diesel functionality
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)
None - This is a backwards-compatible feature addition.
- Fixed QA test to use correct API response fields (
priceinstead ofvalue,formattedinstead ofcode + name) - Updated README examples to match actual API response structure
- Corrected blog post examples for accuracy
- Verified 100% test pass rate (7/7 tests passing)
- All code examples now use correct fields:
price,formatted,code,created_at - Removed references to non-existent
name,value, andunitfields in latest prices response - Added clarification on timeout configuration for historical data queries (120s recommended)
- Historical prices endpoint working correctly with 120s timeout
- All 5 endpoints tested and verified against live API
0.3.0 - 2024-11-25
- Commodities Endpoint:
getCommodities()- Get metadata for all supported commodities - Commodity Categories:
getCommodityCategories()- Get all commodity categories with their commodities - Commodity Details:
getCommodity(code)- Get metadata for a specific commodity by code - New TypeScript interfaces:
Commodity,CommoditiesResponse,CommodityCategory,CategoriesResponse
Now supports 5 endpoints (up from 2):
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 details
0.2.0 - 2024-11-24
- Retry Logic: Automatic retries with configurable strategies (exponential, linear, fixed)
- Timeout Handling: Request timeouts with AbortController
- Debug Logging: Optional debug mode for detailed request/response logging
- TimeoutError: New error class for timeout scenarios
- Smart Error Handling: Intelligent retry logic based on error type
- Rate Limit Handling: Automatic retry with
Retry-Afterheader support
- User-Agent updated to
oilpriceapi-node/0.2.0 - Improved error messages with more context
- Better TypeScript type definitions for configuration options
New configuration options available:
retries: Maximum number of retry attempts (default: 3)retryDelay: Initial delay between retries in ms (default: 1000)retryStrategy: Retry backoff strategy - 'exponential', 'linear', or 'fixed' (default: 'exponential')timeout: Request timeout in milliseconds (default: 30000)debug: Enable debug logging (default: false)
0.1.0 - 2024-11-24
- Initial release
- Basic API client with TypeScript support
- Latest prices endpoint support
- Historical prices endpoint support
- Custom error classes (AuthenticationError, RateLimitError, NotFoundError, ServerError)
- Zero runtime dependencies
- Full TypeScript type definitions
- Comprehensive README documentation
GET /v1/prices/latest- Get latest commodity pricesGET /v1/prices- Get historical commodity prices