{"openapi":"3.1.0","info":{"title":"CompCurve License API","version":"1.0.0","description":"Read-only REST API over monthly US + Canada real-estate license data (~2.5M licenses per monthly snapshot; US rows enriched with matched email/phone and office agent counts).","contact":{"email":"eli@compcurve.com"}},"servers":[{"url":"https://api.compcurve.com"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key issued by CompCurve, format cck_…"},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-API-Key"}}},"security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"paths":{"/v1/health":{"get":{"summary":"Liveness + DB reachability (public)","security":[],"responses":{"200":{"description":"OK"}}}},"/v1/me":{"get":{"summary":"Current key: tier, status, rate limits, monthly quota + usage, scope (geo/fields/history)","responses":{"200":{"description":"Key metadata"}}}},"/v1/usage":{"get":{"summary":"Your request usage by day","parameters":[{"name":"days","in":"query","description":"Window in days (default 30, max 90)","schema":{"type":"integer"}}],"responses":{"200":{"description":"Daily request counts"}}}},"/v1/snapshots":{"get":{"summary":"Loaded monthly snapshots with row counts; each flagged accessible true/false for your key","responses":{"200":{"description":"Snapshot list + meta.history (your history scope)"}}}},"/v1/suggest":{"get":{"summary":"Type-ahead: distinct prefix matches for city / office / last_name","parameters":[{"name":"field","in":"query","required":true,"schema":{"type":"string","enum":["city","office","last_name"]}},{"name":"q","in":"query","required":true,"description":"Prefix, min 2 chars","schema":{"type":"string"}},{"name":"state","in":"query","schema":{"type":"string"}},{"name":"snapshot","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Max 20","schema":{"type":"integer"}}],"responses":{"200":{"description":"Suggestions"}}}},"/v1/licenses/history":{"get":{"summary":"One license across every snapshot your key may read (history add-on), newest first, with a field-level change log","description":"Identify the license with state + license_number, or seed from any row id. Returns rows per snapshot, present_in / missing_in, and `changes` — one entry per tracked field that differs between consecutive months (status, office, expiry, type…). Requires history access: latest-only keys receive 403 history_denied.","parameters":[{"name":"state","in":"query","description":"State/province code (with license_number)","schema":{"type":"string"}},{"name":"license_number","in":"query","description":"Exact license number (with state)","schema":{"type":"string"}},{"name":"id","in":"query","description":"Seed from a row id instead of state + license_number","schema":{"type":"integer"}},{"name":"fields","in":"query","description":"Sparse fieldset (same rules as /v1/licenses)","schema":{"type":"string"}}],"responses":{"200":{"description":"History payload"},"400":{"description":"Missing/invalid identifier"},"403":{"description":"history_denied (no history add-on) or scope_denied"},"404":{"description":"id not found"}}}},"/v1/states":{"get":{"summary":"States/provinces with per-state row counts","parameters":[{"name":"country","in":"query","schema":{"type":"string","enum":["US","CA"]}},{"name":"snapshot","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"State list"}}}},"/v1/stats":{"get":{"summary":"Precomputed snapshot aggregates (status/type vocab, coverage)","parameters":[{"name":"snapshot","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Aggregates blob"}}}},"/v1/licenses":{"get":{"summary":"Query licenses (filters, sort, pagination, sparse fields)","parameters":[{"name":"snapshot","in":"query","description":"Monthly snapshot, e.g. 2026-07. Defaults to latest. Prior months require the history add-on — otherwise 403 history_denied (see /v1/me → scope.history)","schema":{"type":"string"}},{"name":"state","in":"query","description":"Exact state/province code; comma-separable. e.g. CA,TX","schema":{"type":"string"}},{"name":"country","in":"query","description":"US or CA","schema":{"type":"string"}},{"name":"last_name","in":"query","description":"Case-insensitive prefix match","schema":{"type":"string"}},{"name":"office_name","in":"query","description":"Case-insensitive prefix match (use /v1/suggest for autocomplete)","schema":{"type":"string"}},{"name":"license_number","in":"query","description":"Exact license number","schema":{"type":"string"}},{"name":"license_status","in":"query","description":"Exact status (vocab varies by state — see /v1/stats)","schema":{"type":"string"}},{"name":"member_type","in":"query","description":"Exact member type","schema":{"type":"string"}},{"name":"city","in":"query","description":"Exact city","schema":{"type":"string"}},{"name":"postal_code","in":"query","description":"Exact postal code (alias: zip)","schema":{"type":"string"}},{"name":"issued_after","in":"query","description":"ISO date: license issued on/after","schema":{"type":"string"}},{"name":"issued_before","in":"query","description":"ISO date: license issued on/before","schema":{"type":"string"}},{"name":"expires_after","in":"query","description":"ISO date: license expires on/after","schema":{"type":"string"}},{"name":"expires_before","in":"query","description":"ISO date: license expires on/before","schema":{"type":"string"}},{"name":"first_issued_after","in":"query","description":"ISO date","schema":{"type":"string"}},{"name":"first_issued_before","in":"query","description":"ISO date","schema":{"type":"string"}},{"name":"sort","in":"query","description":"Comma-separated sort columns (whitelisted)","schema":{"type":"string"}},{"name":"order","in":"query","description":"asc | desc","schema":{"type":"string"}},{"name":"page","in":"query","description":"1-based page number","schema":{"type":"string"}},{"name":"limit","in":"query","description":"Rows per page (default 100, max 1000)","schema":{"type":"string"}},{"name":"fields","in":"query","description":"Sparse fieldset: comma-separated column names","schema":{"type":"string"}},{"name":"count","in":"query","description":"Set false to skip the total-count query — faster; total/total_pages become null and has_next is inferred from page fill","schema":{"type":"string"}},{"name":"format","in":"query","description":"Response format: json (default), csv, or ndjson. For csv/ndjson, pagination is returned in X-Total-Count / X-Page / X-Has-Next response headers; csv also sends a Content-Disposition download filename","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated license rows"},"400":{"description":"Invalid parameter"},"403":{"description":"scope_denied (geo/field scope) or history_denied (?snapshot= outside history scope)"},"429":{"description":"Rate limited"}}}},"/v1/licenses/{id}":{"get":{"summary":"Single license by internal id (per-snapshot)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"License row"},"403":{"description":"history_denied — row belongs to a snapshot outside your history scope"},"404":{"description":"Not found"}}}}}}