DrillerDB API conventions: errors, rate limits and versioning
DrillerDB has two kinds of HTTP API:
- Public endpoints on drillerdb.com, free and with no key: well depth and water-table lookup, the driller directory and license search, ZIP geocoding, platform stats and conference calendars. They are described in drillerdb.com/openapi.json.
- The DrillerDB Partner API, for read-only access to your own company's data with an API key:
https://console.drillerdb.com/api/partner/v1and, on the classic app,https://app.drillerdb.com/api/v1.
Both follow the conventions below. The MCP server uses the Model Context Protocol and OAuth instead and is not covered here.
Errors
drillerdb.com public endpoints
Every error is JSON with an HTTP status that matches it. The data endpoints (well depth, license lookup, nearby drillers and ZIP geocoding) send two fields:
{"error":"invalid_zip","message":"Enter a 5-digit US ZIP code."}
error is a stable code you can branch on. message is written for a person.
The two conference calendar feeds send one field, error, and it holds a sentence, for example {"error":"Conference not found."}. Branch on the HTTP status for those.
Two errors apply to any /api path:
-
404 when no endpoint exists at that path. The body adds
hintanddocumentation:{"error":"not_found","message":"No API endpoint at /api/zzz.","hint":"The public endpoints are listed in https://drillerdb.com/openapi.json.","documentation":"https://drillerdb.com/openapi.json"} -
405 when the endpoint exists but does not accept that method. Every public endpoint is GET. The response carries an
Allowheader that lists the methods the endpoint accepts (GET, HEAD, OPTIONS;GET, HEADon/api/stats) and the same four fields, witherrorset tomethod_not_allowed.
Partner API
Errors use an envelope with a request ID:
{"error":{"code":"API_KEY_REQUIRED","message":"This endpoint requires an X-API-Key header."},"meta":{"request_id":"req_d7b6ab54ad5b2532"},"links":{"self":"/api/partner/v1/projects"}}
Branch on error.code, for example API_KEY_REQUIRED (401), INSUFFICIENT_SCOPE (403) or RATE_LIMITED (429). On the classic app, error.hint says what to do next and links.documentation points at the OpenAPI document. Quote meta.request_id when you ask us about a specific call.
Rate limits
drillerdb.com
The limit is 500 requests per IP address per minute, counted across page views and API requests together. It is not a per-endpoint limit: loading pages from the same address uses the same quota.
Every /api response the limiter counted carries two header fields, as defined in draft-ietf-httpapi-ratelimit-headers (version 11):
RateLimit-Policy: "default";q=500;w=60
RateLimit: "default";r=482;t=37
q=500;w=60: the quota, 500 requests in a 60-second window.r: requests you can still make now.t: seconds until the oldest counted request leaves the window and quota starts to come back.
Over the limit, the response is a 429 with Retry-After (seconds) and this body:
{"error":"rate_limited","message":"Too many requests. Please try again shortly."}
Wait at least the Retry-After time before the next request. Ignore the RateLimit fields on a response that came from a cache (one with an Age header above 0), because the numbers are from when it was first sent.
Partner API
Each API key has a per-minute and a per-day limit. A new key starts at 120 requests per minute and 5,000 per day. Over either one, the response is a 429 with error.code RATE_LIMITED and a Retry-After header in seconds.
On the classic app (https://app.drillerdb.com/api/v1), a request that gets as far as the limit check also gets the two RateLimit fields back, with one entry for each of the key's windows. The limit check comes after the API key and its scope are accepted, so a 401 or 403 carries no fields. The windows follow the UTC clock: the minute window ends at the next full minute and the day window at midnight UTC.
RateLimit-Policy: "minute";q=120;w=60, "day";q=5000;w=86400
RateLimit: "minute";r=117;t=42, "day";r=4980;t=31000
qandw: the key's own limit and the window length in seconds.r: requests the key can still make in that window.t: seconds until that window ends.
A 429 carries the same fields beside Retry-After. A 500 error carries none, and neither does a key with no limits set. Browser clients on another origin can read the fields, because the API lists them in Access-Control-Expose-Headers.
The console Partner API (https://console.drillerdb.com/api/partner/v1) does not send RateLimit fields yet.
Versioning and deprecation
- The version is in the path. The Partner API's major version is part of every URL:
/api/partner/v1on the console and/api/v1on the classic app. - Additive changes stay in the current version. New response fields, new optional parameters and new endpoints can appear in v1 at any time. Write your client to ignore fields it does not know.
- A breaking change gets a new major version path, such as
/api/partner/v2. Removing or renaming a field, changing a type, or making an optional parameter required is a breaking change. - A deprecated version says so on every response. It sends a
Deprecationheader (RFC 9745), aSunsetheader with the date it stops answering (RFC 8594), and aLinkheader withrel="deprecation"pointing at the migration notes. - At least 12 months pass between the date a version first sends the
Deprecationheader and itsSunsetdate.
No version is deprecated today.