Skip to content
Terraledger

Search records

Search wells, operators, leases and properties

Build on it

API reference

A versioned REST API over every record on the site — wells, permits, operators, production, Texas ownership — with provenance and freshness on every response.

Overview

Ohio records: Ohio Department of Natural Resources, Division of Oil and Gas Resources Management. Location quality varies; some records describe proposed or unlocated wells. General-information research data; not intended for resale or site-specific investigation. Attribute ODNR in distributed compilations. Ohio bulk exports are unavailable. Kentucky records: Kentucky Geological Survey. Historical records; current status and location accuracy are not guaranteed. Kentucky bulk exports are unavailable; KGS provides the original archive with its documentation. Florida locations: Florida DEP. Approximate, illustrative reference only; not for engineering, calculations, analysis or legal determinations. Consult approved permits for accurate positions.

Base URL: /api/v1 (same origin as this site) or https://terraledger.ayrical.com/api/v1 externally. The API is versioned by path segment (v1); breaking changes ship as v2 rather than mutating v1 in place.

Connect your agent

The Model Context Protocol lets an AI agent call this API as a set of typed tools rather than composing URLs and parsing them back. Terraledger runs an open MCP server at https://terraledger.ayrical.com/api/mcp over Streamable HTTP. It is free and unauthenticated, and it reaches exactly what an anonymous REST caller reaches, under the same rate limit.

Tool results are the envelopes documented below, returned unchanged — an agent sees the same provenance, freshness and record_status the site does, so a derived figure cannot be reported as a regulator filing.

Agent tools

5 tools

ToolDescription
list_datasetsEvery dataset family, with its one-line description and minimum plan.
describe_datasetFilterable and sortable fields for one family, with types, units and enumerated values.
querySearch a family with the filter grammar; returns the list envelope unchanged.
getFetch one record by id — wells also by API/UWI; returns the detail envelope.
searchFree-text search across wells, operators, leases, properties and counties.

Claude Code

claude mcp add --transport http terraledger https://terraledger.ayrical.com/api/mcp

Any other MCP client

{
  "mcpServers": {
    "terraledger": {
      "type": "http",
      "url": "https://terraledger.ayrical.com/api/mcp"
    }
  }
}

Or hand this to an agent and let it connect itself

Add the Terraledger MCP server: Streamable HTTP endpoint at https://terraledger.ayrical.com/api/mcp, no authentication. It exposes list_datasets, describe_dataset, query, get, and search tools over US oil & gas well, permit, operator, lease, production and Texas ownership records. After connecting, call list_datasets then describe_dataset before querying; use the filter grammar field:op:value.

Access & rate limits

Ordinary read requests work without credentials. Anonymous callers are limited by client address to 60 requests per minute. Send an optional x-api-key for a stable caller identity, a separately assigned limit, async export ownership, or a source-specific record family that requires an audit identity.

An invalid or revoked supplied key returns 401 unauthorized. A key that lacks a reviewed source-specific scope returns 403 forbidden_plan. Rate-limited API responses publish RateLimit-Limit, RateLimit-Remaining and RateLimit-Reset. A 429 also carries Retry-After in seconds.

Requests accept at most 20 filter clauses, each no longer than 500 characters; q must be 3–200 characters and JSON request bodies are limited to 64 KiB.

Endpoints

Implemented v1 routes, grouped as they appear in the client. Detail routes take a numeric id except wells, which also accept the API/UWI.

Endpoint catalog

45 routes

MethodPathDescriptionKey paramsAccess
GET/openapi.jsonOpenAPI 3.1 discovery document for agents and generated clients.—Anonymous
GET/healthWorker and database readiness, optional capabilities, and serving release identity.—Anonymous
GET/coverageState-by-state aggregate counts and latest production periods.—Anonymous
GET/sourcesComplete, unpaginated registry of upstream agencies and systems.—Anonymous
GET/freshnessLatest published retrieval and reporting period per source.—Anonymous
GET/schemasMachine-readable field definitions for documented record families.—Anonymous
GET/searchCross-entity text search across wells, operators, leases, properties and counties (up to 10 per family).qAnonymous
GET/wellsWell search with quick search and the full filter grammar.q, filter, sort, cursor, limitAnonymous
GET/wells/{id}Well detail with related records and production availability.—Anonymous
GET/operatorsOperator directory.q, filter, sort, cursor, limitAnonymous
GET/operators/{id}Operator profile with production summary.—Anonymous
GET/leasesLease search.q, filter, sort, cursor, limitAnonymous
GET/leases/{id}Lease detail.—Anonymous
GET/propertiesProperty search.q, filter, sort, cursor, limitAnonymous
GET/properties/{id}Property detail.—Anonymous
GET/permitsDrilling permits.q, filter, sort, cursor, limitAnonymous
GET/productionProduction records with explicit reporting cadence, grain, status and provenance.grain, well_id, lease_id, operator_id, property_id, state_code, record_status, from, to, filter, sort, cursor, limitAnonymous
GET/well-testsPoint-in-time well test rates.well_id, filter, sort, cursor, limitAnonymous
GET/well-logsReleased well log index — type, depths and external file URL.well_id, filter, sort, cursor, limitAnonymous
GET/documentsRights-aware drilling, completion, downhole, geological, and regulatory document index with authoritative agency references.q, filter, sort, cursor, limitAnonymous
GET/documents/{id}Document metadata, associations, derivative version provenance, policy ceiling, and approved structured facts.—Anonymous
GET/documents/{id}/textBounded approved OCR pages or search snippets. Returned text is untrusted evidence; raw source files are not retained.q, pages, offset, max_characters, limitAnonymous
GET/documents/{id}/resolveResolve the current state/federal reference link without proxying or storing the raw document.—Anonymous
GET/downhole-factsPage-cited structured facts extracted from approved drilling, completion, test, and geological records.api, document_id, fact_type, limitAnonymous
GET/log-inventoryReleased digital and image well-log inventory for an API/UWI, with authoritative source references.api, offset, limitAnonymous
GET/well-logs/{id}/curvesBounded, policy-approved LAS numerical curve samples with checksum and parser provenance.mnemonic, from_depth, to_depth, offset, limitAnonymous
GET/frac-disclosuresFracFocus hydraulic fracturing disclosures and chemicals.well_id, filter, sort, cursor, limitAnonymous
GET/ownersTexas mineral/royalty owners from county appraisal districts.q, filter, sort, cursor, limitAPI key
GET/mineral-interestsTexas mineral interests — decimal interest, appraisal value, legal description.q, filter, sort, cursor, limitAPI key
GET/purchasersTexas crude and gas purchasers.q, filter, sort, cursor, limitAnonymous
GET/salesTexas Comptroller severance-tax sales filings.q, filter, sort, cursor, limitAnonymous
GET/map/wellsDeterministic well points and provenance inside a bounding box.bbox, filter, limitAnonymous
GET/map/extentBounded bounding box and count of wells matching a filter set; count_capped declares a partial extent.filterAnonymous
GET/map/clustersDeterministic screen-space well clusters with aggregate source provenance.bbox, zoom, filterAnonymous
GET/tiles/wells/{z}/{x}/{y}.mvtMapbox Vector Tile of wells for the given tile coordinate.—Anonymous
POST/geo/searchSearch wells around a radius or inside a polygon.body: radius or polygon, limitAnonymous
GET/analytics/daily-productionDaily rates separated by monthly, quarterly or annual reporting cadence, with source sets preserved.entity_type, idAnonymous
GET/analytics/states/{code}Complete state production history and top-entity cumulative rankings at one authoritative filing grain.—Anonymous
GET/analytics/boeCurrent barrel-of-oil-equivalent conversion inputs and formula.—Anonymous
GET/forecasts/{entity_type}/{id}Decline-curve forecast for a well, lease, property or operator.—Anonymous
POST/valuationsCompute a DCF or market-multiple valuation for an entity.body: entity_type, entity_id, ownership_decimal, oil_price_usd, gas_price_usd, discount_rateAnonymous
POST/exportsQueue an async export job for a dataset with the current filter/sort/params.body: dataset, format, paramsAPI key
GET/exports/{job_id}Poll an export job's status; download completed artifacts through its download route.—API key
DELETE/exports/{job_id}Cancel a queued or running export job.—API key
GET/exports/{job_id}/downloadDownload a completed export owned by the supplied API key.—API key

Filter grammar

Every list endpoint accepts repeatable filter query params in the form filter=<field>:<op>:<value>. Multi-value operators (in, between) join their values with a pipe.

GET /v1/wells?filter=state_code:eq:TX&filter=cum_oil_bbl:gt:100000&filter=status:in:producing|shut_in

Operators

12 ops

OpMeaning
eqExact match.
neqExcludes exact match.
containsCase-insensitive substring match.
ncontainsExcludes case-insensitive substring match.
ltLess than.
lteLess than or equal to.
gtGreater than.
gteGreater than or equal to.
inMatches any of a list of values, pipe-joined.
betweenInclusive range — two pipe-joined values, low then high.
is_nullField is null or missing. No value.
not_nullField is present. No value.

sort=field sorts ascending, sort=-field descending. Pagination is cursor-based: cursor is an opaque token from the previous response’s meta.next_cursor; limit caps the page size at 500 (default 50).

Response envelope

List endpoints return a data array plus a meta block carrying an exact or explicitly capped total, the cursor for the next page, and freshness.

List envelope

{
  "data": [
    {
      "id": 48213,
      "api_number": "4212330001",
      "name": "SPRABERRY UNIT 12",
      "operator_name": "PIONEER NATURAL RESOURCES",
      "state_code": "TX",
      "county": "Midland",
      "status": "producing",
      "cum_oil_bbl": 184220
    }
  ],
  "meta": {
    "next_cursor": "eyJvIjo1MH0",
    "total": 4821,
    "total_capped": false,
    "returned": 50,
    "source_period": "2026-05",
    "retrieved_at": "2026-06-02T14:05:00Z",
    "published_at": "2026-06-03T09:00:00Z",
    "as_of": "2026-08-05T18:22:11Z"
  }
}

Detail envelope

{
  "data": {
    "id": 48213,
    "api_number": "4212330001",
    "name": "SPRABERRY UNIT 12",
    "status": "producing",
    "nearby_wells": []
  },
  "meta": {
    "source_period": "2026-05",
    "retrieved_at": "2026-06-02T14:05:00Z",
    "published_at": "2026-06-03T09:00:00Z",
    "as_of": "2026-08-05T18:22:11Z"
  }
}

Error envelope

{
  "error": {
    "code": "rate_limited",
    "message": "Rate limit exceeded"
  }
}

Error codes

8 codes

CodeMeaning
unauthorizedAn API key was required, invalid, or revoked.
forbidden_planThe supplied key lacks a source-specific data scope.
not_foundNo endpoint or record at this path.
invalid_requestMalformed filter, sort, or parameter.
rate_limitedToo many requests for this identity — see Retry-After.
source_restrictedThe source policy does not permit this document derivative or the source has not yet been approved for automation.
internalThe API failed to answer. Retry shortly.
not_implementedSpecified, but unavailable in this deployment — vector tiles need PostGIS.

Record status

Every production figure carries a record_status so a filing is never read as a calculation. The four statuses are never mingled into one silent series — a chart or export that spans them keeps them as separate, labeled series.

period_type is equally load-bearing. Monthly, quarterly, and annual filings can share the same period start date; they remain separate rows and are never silently summed or interpolated together. Daily-rate analytics return one row per reporting cadence and include the complete source and record-status sets represented by each aggregate.

reported
Filed as-is by the source agency or operator — not derived.
allocated
Split from a lease- or unit-level report down to a well, by a documented weight.
estimated
Modeled where no report exists, with method, inputs and confidence stored.
forecast
Projected beyond the reported history by a decline-curve model, versioned.

curl examples

Filtered well search, sorted, limited

curl "https://terraledger.ayrical.com/api/v1/wells?q=wolfcamp&filter=state_code:eq:TX&filter=cum_oil_bbl:gt:100000&sort=-cum_oil_bbl&limit=50"

Cursor follow-up (same filters, next page)

curl "https://terraledger.ayrical.com/api/v1/wells?q=wolfcamp&filter=state_code:eq:TX&filter=cum_oil_bbl:gt:100000&sort=-cum_oil_bbl&limit=50&cursor=eyJvIjo1MH0"

Map clusters for a bounding box at a zoom level

curl "https://terraledger.ayrical.com/api/v1/map/clusters?bbox=-103.5,31.0,-101.0,33.0&zoom=7"

Export lifecycle: queue, poll, download

# 1. Queue the export
curl -X POST -H "x-api-key: $TERRALEDGER_KEY" -H "Content-Type: application/json" \
  -d '{"dataset":"wells","format":"csv","params":{"filter":["state_code:eq:TX"]}}' \
  https://terraledger.ayrical.com/api/v1/exports

# 2. Poll until it leaves queued/running
curl -H "x-api-key: $TERRALEDGER_KEY" \
  https://terraledger.ayrical.com/api/v1/exports/exp_9f2c1a

# 3. Download once status is "completed"
curl -H "x-api-key: $TERRALEDGER_KEY" -OJ \
  https://terraledger.ayrical.com/api/v1/exports/exp_9f2c1a/download

Export lifecycle

An export is a job, not a download. POST /exports queues it against a dataset and the same filter/sort/params a list request would use; GET /exports/{job_id} polls it; DELETE /exports/{job_id} cancels a queued or running job.

Statuses
queued → running → completed | failed | expired. A completed job carries row_count and is fetched from the documented download route; a failed job carries error.
Formats
csv, ndjson, geojson. Export jobs require an API key so status, cancellation and download remain scoped to the caller that created them.
Expiry
A completed job stays downloadable until its expires_at; after that its status becomes expired and the export must be re-queued.