{"openapi":"3.1.0","info":{"title":"DEEP Data API","version":"0.2.0","description":"Caribbean and OECS structured data for developers and AI agents, with source provenance. A DEEP Works product. Informational only — not financial, legal, or safety advice. Billing opens soon. Successful feed reads send ETag and Cache-Control: private, max-age=15. Public status, the NHC sample, and this document are cacheable without a key. History and reports are cursor pages. GET /v1/usage is not metered."},"servers":[{"url":"https://data.wearedeepworks.com","description":"DEEP Data"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","bearerFormat":"dd_live_","description":"API key created in the dashboard. Send Authorization: Bearer dd_live_…"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","examples":["unauthorized","rate_limited","not_found","payment_required","invalid_query","database_unavailable"]},"message":{"type":"string"}},"required":["code","message"]}},"required":["error"]},"Page":{"type":"object","properties":{"limit":{"type":"integer"},"next_cursor":{"type":"string","nullable":true}},"required":["limit","next_cursor"]},"Source":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"fetched_at":{"type":"string","format":"date-time","nullable":true},"snapshot_id":{"type":"string","nullable":true}},"required":["url","fetched_at","snapshot_id"]},"FeedEnvelope":{"type":"object","properties":{"feed":{"type":"string"},"as_of":{"type":"string","format":"date-time","nullable":true},"fetched_at":{"type":"string","format":"date-time","nullable":true},"licence":{"type":"string"},"attribution":{"type":"string"},"disclaimer":{"type":"string"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/Source"}},"data":{},"name":{"type":"string"},"status":{"type":"string"},"data_omitted":{"type":"boolean"},"has_record":{"type":"boolean"}},"required":["feed","as_of","fetched_at","licence","attribution","disclaimer","sources","data"]}}},"paths":{"/v1/feeds":{"get":{"summary":"List feeds","description":"Catalog with licence, status, and source timestamps. Metered. The list does not include record payloads. Responses carry ETag and a private 15 second cache.","security":[{"bearer":[]}],"responses":{"200":{"description":"Feed catalog","headers":{"ETag":{"schema":{"type":"string"}}}},"304":{"description":"Not modified. Send If-None-Match with the previous ETag. No body and no credit debit. The response still counts toward the per-key rate limit."},"400":{"description":"invalid_query. The limit, cursor, omit, or feed parameter was not valid. Not counted against the quota."},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Send Authorization: Bearer dd_live_…"}}}}},"429":{"description":"Rate limit. Free is 10/min and 100/day. Starter is 60/min. Pro is 300/min. A 304 counts. An invalid query does not."}}}},"/v1/feeds/{slug}":{"get":{"summary":"Latest feed record","description":"Full provenance envelope. Metered. data is null until a successful ingest. omit=data skips the payload and sets data_omitted and has_record. Send If-None-Match to revalidate.","security":[{"bearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","examples":["nhc-storms"]}},{"name":"omit","in":"query","required":false,"schema":{"type":"string","enum":["data"]},"description":"Pass data to leave payloads out. Detail sets data to null and adds data_omitted plus has_record. History omits each change payload."}],"responses":{"200":{"description":"Envelope","headers":{"ETag":{"schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedEnvelope"},"example":{"feed":"nhc-storms","as_of":"2026-10-28T03:00:00.000Z","fetched_at":"2026-10-28T03:03:31.172Z","licence":"us-gov-public-domain","attribution":"United States government work. Public domain in the United States.","disclaimer":"Informational only — not financial, legal, or safety advice. Verify with the cited source.","sources":[{"url":"https://www.nhc.noaa.gov/CurrentStorms.json","fetched_at":"2026-10-28T03:03:31.172Z","snapshot_id":"0982e061-fd23-46ba-b54b-e031e188ba6b"}],"data":{"storms":[],"caribbean_interest":false}}}}},"304":{"description":"Not modified. Send If-None-Match with the previous ETag. No body and no credit debit. The response still counts toward the per-key rate limit."},"400":{"description":"invalid_query. The limit, cursor, omit, or feed parameter was not valid. Not counted against the quota."},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Send Authorization: Bearer dd_live_…"}}}}},"404":{"description":"Unknown feed"},"429":{"description":"Rate limit. Free is 10/min and 100/day. Starter is 60/min. Pro is 300/min. A 304 counts. An invalid query does not."}}}},"/v1/feeds/{slug}/sample":{"get":{"summary":"Public sample","description":"Unauthenticated sample for nhc-storms. Returns the latest stored envelope when one exists, otherwise a committed fixture with fetched_at null. Not metered. Cached publicly. Other slugs return 404.","security":[],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","enum":["nhc-storms"]}}],"responses":{"200":{"description":"Sample envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FeedEnvelope"},"example":{"sample":true,"sample_kind":"live","feed":"nhc-storms","as_of":"2026-10-28T03:00:00.000Z","fetched_at":"2026-10-28T03:03:31.172Z","licence":"us-gov-public-domain","attribution":"United States government work. Public domain in the United States.","disclaimer":"Informational only — not financial, legal, or safety advice. Verify with the cited source.","sources":[{"url":"https://www.nhc.noaa.gov/CurrentStorms.json","fetched_at":"2026-10-28T03:03:31.172Z","snapshot_id":"0982e061-fd23-46ba-b54b-e031e188ba6b"}],"data":{"storms":[],"caribbean_interest":false}}}}},"304":{"description":"Not modified"},"404":{"description":"This feed has no public sample"}}}},"/v1/feeds/{slug}/history":{"get":{"summary":"Feed change history","description":"Append-only record_changes, newest first. Metered. Default limit 30, maximum 100. page.next_cursor is null on the last page. omit=data leaves payloads out. A Link rel=next header is set when another page exists.","security":[{"bearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","examples":["nhc-storms"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100},"description":"Page size. History defaults to 30. Reports default to 10. Usage defaults to 50."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque next_cursor from the previous page. Invalid cursors return 400 invalid_query."},{"name":"omit","in":"query","required":false,"schema":{"type":"string","enum":["data"]},"description":"Pass data to leave payloads out. Detail sets data to null and adds data_omitted plus has_record. History omits each change payload."}],"responses":{"200":{"description":"Change page","content":{"application/json":{"schema":{"type":"object","properties":{"feed":{"type":"string"},"licence":{"type":"string"},"disclaimer":{"type":"string"},"changes":{"type":"array"},"page":{"$ref":"#/components/schemas/Page"}}}}}},"304":{"description":"Not modified. Send If-None-Match with the previous ETag. No body and no credit debit. The response still counts toward the per-key rate limit."},"400":{"description":"invalid_query. The limit, cursor, omit, or feed parameter was not valid. Not counted against the quota."},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Send Authorization: Bearer dd_live_…"}}}}},"404":{"description":"Unknown feed"},"429":{"description":"Rate limit. Free is 10/min and 100/day. Starter is 60/min. Pro is 300/min. A 304 counts. An invalid query does not."}}}},"/v1/feeds/{slug}/charts":{"get":{"summary":"Feed charts","description":"Chart series stored as numeric points. Metered. Cached like other feed reads.","security":[{"bearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","examples":["nhc-storms"]}}],"responses":{"200":{"description":"Chart series"},"304":{"description":"Not modified. Send If-None-Match with the previous ETag. No body and no credit debit. The response still counts toward the per-key rate limit."},"400":{"description":"invalid_query. The limit, cursor, omit, or feed parameter was not valid. Not counted against the quota."},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Send Authorization: Bearer dd_live_…"}}}}},"404":{"description":"Unknown feed"},"429":{"description":"Rate limit. Free is 10/min and 100/day. Starter is 60/min. Pro is 300/min. A 304 counts. An invalid query does not."}}}},"/v1/feeds/{slug}/reports":{"get":{"summary":"Feed reports","description":"Ingest reports, newest first. Metered. Default limit 10, maximum 100. page.next_cursor continues the list.","security":[{"bearer":[]}],"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","examples":["nhc-storms"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100},"description":"Page size. History defaults to 30. Reports default to 10. Usage defaults to 50."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque next_cursor from the previous page. Invalid cursors return 400 invalid_query."}],"responses":{"200":{"description":"Report page"},"304":{"description":"Not modified. Send If-None-Match with the previous ETag. No body and no credit debit. The response still counts toward the per-key rate limit."},"400":{"description":"invalid_query. The limit, cursor, omit, or feed parameter was not valid. Not counted against the quota."},"401":{"description":"Missing or unknown API key","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Send Authorization: Bearer dd_live_…"}}}}},"404":{"description":"Unknown feed"},"429":{"description":"Rate limit. Free is 10/min and 100/day. Starter is 60/min. Pro is 300/min. A 304 counts. An invalid query does not."}}}},"/v1/status":{"get":{"summary":"Public status","description":"Not metered. ok means a successful ingest inside the stale window. degraded means the upstream refused the fetch and no records were written. Optional feed query returns one catalog slug. Cached publicly for 30 seconds.","security":[],"parameters":[{"name":"feed","in":"query","required":false,"schema":{"type":"string","examples":["nhc-storms"]},"description":"One catalog slug. Unknown slugs return 404."}],"responses":{"200":{"description":"Feed health","headers":{"ETag":{"schema":{"type":"string"}}}},"304":{"description":"Not modified"},"400":{"description":"feed was not a slug"},"404":{"description":"Unknown feed"}}}},"/v1/openapi":{"get":{"summary":"This document","security":[],"responses":{"200":{"description":"OpenAPI document"},"304":{"description":"Not modified"}}}},"/v1/usage":{"get":{"summary":"Usage for the API key","description":"Not metered. Default limit 50, maximum 100. page.next_cursor continues the list. Checking usage does not debit a credit.","security":[{"bearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100},"description":"Page size. History defaults to 30. Reports default to 10. Usage defaults to 50."},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"},"description":"Opaque next_cursor from the previous page. Invalid cursors return 400 invalid_query."}],"responses":{"200":{"description":"Credit balance and recent calls"},"400":{"description":"invalid_query"},"401":{"description":"Missing or unknown API key"}}}},"/v1/billing/checkout":{"post":{"summary":"Billing opens soon"}},"/v1/billing/portal":{"post":{"summary":"Billing opens soon"}},"/v1/billing/webhook":{"post":{"summary":"Billing webhook"}}}}