{"openapi":"3.1.0","info":{"title":"Locastica API","version":"1.0.0","summary":"Official-source property licensing intelligence for England.","description":"Locastica exposes property licensing intelligence with council evidence, published fee context, freshness metadata, and public reference endpoints."},"servers":[{"url":"https://locastica.com"}],"tags":[{"name":"Licensing","description":"Property licensing lookup by postcode."},{"name":"Discovery","description":"Public reference endpoints shown on the Locastica site."}],"components":{"securitySchemes":{"bearerApiKey":{"type":"http","scheme":"bearer","bearerFormat":"API key","description":"Use an API key created in /account/api-keys. Keys begin with `lk_live_`."},"xApiKey":{"type":"apiKey","in":"header","name":"x-api-key","description":"Alternative header when a client cannot send Authorization."}},"headers":{"XApiMonthlyLimit":{"schema":{"type":"string"},"description":"Account-wide monthly request allowance for API-enabled plans."},"XApiMonthlyUsed":{"schema":{"type":"string"},"description":"Requests already used in the current monthly window across active keys."},"XApiMonthlyRemaining":{"schema":{"type":"string"},"description":"Requests still available in the current monthly window."},"XApiMonthlyReset":{"schema":{"type":"string","format":"date-time"},"description":"ISO timestamp for the next monthly usage reset."},"XApiBurstLimit":{"schema":{"type":"string"},"description":"Per-key burst ceiling in requests per minute."},"XRateLimitLimit":{"schema":{"type":"string"},"description":"Daily browser lookup limit for non-API callers."},"XRateLimitRemaining":{"schema":{"type":"string"},"description":"Daily browser lookup requests remaining."},"XRateLimitReset":{"schema":{"type":"string","format":"date-time"},"description":"Reset timestamp for the browser daily lookup window."}},"schemas":{"ErrorResponse":{"type":"object","required":["error"],"properties":{"error":{"type":"string"},"code":{"type":"string"},"details":{"type":"string"}}},"RedactedField":{"type":"object","required":["redacted","message","upgradeUrl"],"properties":{"redacted":{"type":"boolean","const":true},"message":{"type":"string"},"upgradeUrl":{"type":"string"}}},"LookupWard":{"type":["object","null"],"properties":{"code":{"type":"string"},"name":{"type":"string"}},"required":["code","name"]},"LookupCouncil":{"type":["object","null"],"properties":{"code":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"},"website":{"type":["string","null"],"format":"uri"},"licensingUrl":{"type":["string","null"],"format":"uri"},"dataQuality":{"type":"string"},"lastVerified":{"type":["string","null"],"format":"date-time"}},"required":["code","name","region","website","licensingUrl","dataQuality","lastVerified"]},"LookupScheme":{"type":"object","required":["id","type","name","status","lifecycleStatus","coverageType","fees","sourceUrl","confidence","lastVerified"],"properties":{"id":{"type":"string"},"type":{"type":"string"},"name":{"type":"string"},"status":{"type":"string"},"lifecycleStatus":{"type":["string","null"]},"coverageType":{"type":"string"},"fees":{"oneOf":[{"type":"object","additionalProperties":{"type":["number","string","boolean","null"]}},{"$ref":"#/components/schemas/RedactedField"}]},"sourceUrl":{"oneOf":[{"type":"string","format":"uri"},{"type":"null"},{"$ref":"#/components/schemas/RedactedField"}]},"confidence":{"type":["number","null"]},"lastVerified":{"type":["string","null"],"format":"date-time"}}},"LicensingLookupResponse":{"type":"object","required":["postcode","ward","council","schemes","coverage"],"properties":{"postcode":{"type":"string"},"ward":{"$ref":"#/components/schemas/LookupWard"},"council":{"$ref":"#/components/schemas/LookupCouncil"},"schemes":{"type":"array","items":{"$ref":"#/components/schemas/LookupScheme"}},"coverage":{"type":"string"},"message":{"type":"string"}}},"CouncilStats":{"type":"object","required":["total","withSchemes","withFullData","withPartialData","withMinimalData","coverage"],"properties":{"total":{"type":"integer"},"withSchemes":{"type":"integer"},"withFullData":{"type":"integer"},"withPartialData":{"type":"integer"},"withMinimalData":{"type":"integer"},"coverage":{"type":"object","required":["full","partial","minimal"],"properties":{"full":{"type":"integer"},"partial":{"type":"integer"},"minimal":{"type":"integer"}}}}},"TimelineTrustMetadata":{"type":"object","required":["sources","confidence","vintage"],"properties":{"sources":{"type":"array","items":{"type":"string","format":"uri"}},"confidence":{"type":"string","enum":["low","medium","high"]},"vintage":{"type":"string","format":"date-time"}}},"TimelineCoverageBadge":{"type":"object","required":["geo","ruleset","data"],"properties":{"geo":{"type":"object","required":["scope"],"properties":{"scope":{"type":"string"}}},"ruleset":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"data":{"type":"object","required":["level"],"properties":{"level":{"type":"string"}}}}},"TimelineItem":{"type":"object","required":["id","title","description","date","phase","status","category","ruleset_id","effective_from","trust_metadata","coverage_badge"],"properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"date":{"type":"string"},"phase":{"type":"string"},"status":{"type":"string","enum":["past","upcoming","current"]},"category":{"type":"string","enum":["prs_database","possession","licensing","ombudsman","mtd","general"]},"ruleset_id":{"type":"string"},"effective_from":{"type":"string"},"trust_metadata":{"$ref":"#/components/schemas/TimelineTrustMetadata"},"coverage_badge":{"$ref":"#/components/schemas/TimelineCoverageBadge"}}},"TimelineResponse":{"type":"object","required":["items","total","coverage_badge","trust_metadata","user_id"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/TimelineItem"}},"total":{"type":"integer"},"coverage_badge":{"$ref":"#/components/schemas/TimelineCoverageBadge"},"trust_metadata":{"$ref":"#/components/schemas/TimelineTrustMetadata"},"user_id":{"type":["string","null"]}}}},"responses":{"BadRequest":{"description":"Missing or invalid request input.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"postcode required"}}}},"Unauthorized":{"description":"Authentication failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Invalid API key","code":"invalid_api_key"}}}},"Forbidden":{"description":"Account plan is not entitled to the requested API access.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"API access is no longer available on this account plan","code":"plan_ineligible"}}}},"TooManyRequests":{"description":"Allowance or burst limit reached.","headers":{"XApiMonthlyLimit":{"$ref":"#/components/headers/XApiMonthlyLimit"},"XApiMonthlyUsed":{"$ref":"#/components/headers/XApiMonthlyUsed"},"XApiMonthlyRemaining":{"$ref":"#/components/headers/XApiMonthlyRemaining"},"XApiMonthlyReset":{"$ref":"#/components/headers/XApiMonthlyReset"},"XApiBurstLimit":{"$ref":"#/components/headers/XApiBurstLimit"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Monthly API limit exceeded","code":"monthly_limit_exceeded"}}}},"InternalServerError":{"description":"Unhandled server error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Internal server error"}}}}}},"paths":{"/api/v1/licensing/lookup":{"get":{"tags":["Licensing"],"summary":"Lookup licensing requirements by postcode","description":"Returns council context, scheme rows, fee visibility, source links, freshness, and coverage for one postcode lookup.","security":[{"bearerApiKey":[]},{"xApiKey":[]}],"parameters":[{"in":"query","name":"postcode","required":true,"schema":{"type":"string"},"description":"UK postcode to resolve."}],"responses":{"200":{"description":"Successful licensing lookup.","headers":{"XApiMonthlyLimit":{"$ref":"#/components/headers/XApiMonthlyLimit"},"XApiMonthlyUsed":{"$ref":"#/components/headers/XApiMonthlyUsed"},"XApiMonthlyRemaining":{"$ref":"#/components/headers/XApiMonthlyRemaining"},"XApiMonthlyReset":{"$ref":"#/components/headers/XApiMonthlyReset"},"XApiBurstLimit":{"$ref":"#/components/headers/XApiBurstLimit"},"XRateLimitLimit":{"$ref":"#/components/headers/XRateLimitLimit"},"XRateLimitRemaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"XRateLimitReset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LicensingLookupResponse"},"example":{"postcode":"SE17 1PU","ward":{"code":"E05014156","name":"Faraday"},"council":{"code":"E09000028","name":"London Borough of Southwark","region":"London","website":"https://www.southwark.gov.uk","licensingUrl":"https://www.southwark.gov.uk/housing/private-tenants-and-landlords/private-rented-property-licensing/apply-private-rented-1","dataQuality":"FULL","lastVerified":"2026-03-15T00:00:00.000Z"},"schemes":[{"id":"scheme_southwark_selective","type":"selective","name":"Selective licensing","status":"active","lifecycleStatus":null,"coverageType":"COUNCIL","fees":{"newApplicationFee":945,"renewalFee":750},"sourceUrl":"https://www.southwark.gov.uk/housing/private-tenants-and-landlords/private-rented-property-licensing/apply-private-rented-1","confidence":0.92,"lastVerified":"2026-03-15T00:00:00.000Z"}],"coverage":"FULL"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"},"500":{"description":"Lookup failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Lookup failed","details":"Error: upstream failure"}}}}}}},"/api/v1/stats":{"get":{"tags":["Discovery"],"summary":"Return council coverage statistics","description":"Returns database-backed council counts and quality percentages used by public product surfaces.","responses":{"200":{"description":"Current council coverage statistics.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CouncilStats"},"example":{"total":317,"withSchemes":275,"withFullData":228,"withPartialData":47,"withMinimalData":42,"coverage":{"full":72,"partial":15,"minimal":13}}}}},"500":{"description":"Statistics request failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":"Failed to fetch council statistics"}}}}}}},"/api/v1/timeline":{"get":{"tags":["Discovery"],"summary":"Return the product timeline feed","description":"Returns upcoming England-wide obligation milestones with trust metadata and coverage badges.","parameters":[{"in":"query","name":"category","required":false,"schema":{"type":"string","enum":["prs_database","possession","licensing","ombudsman","mtd","general"]}},{"in":"query","name":"from","required":false,"schema":{"type":"string","format":"date"}},{"in":"query","name":"to","required":false,"schema":{"type":"string","format":"date"}}],"responses":{"200":{"description":"Timeline feed response.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimelineResponse"},"example":{"items":[{"id":"rra-2025-phase1","title":"Renters' Rights Act - Phase 1","description":"Section 21 abolition, new possession grounds, PRS Database initial registration","date":"2026-05-01","phase":"Phase 1","status":"current","category":"prs_database","ruleset_id":"RRA-ENG-2025","effective_from":"2026-05-01","trust_metadata":{"sources":["https://www.gov.uk/government/collections/renters-rights-bill"],"confidence":"high","vintage":"2026-04-18T00:00:00.000Z"},"coverage_badge":{"geo":{"scope":"ENGLAND"},"ruleset":{"id":"RRA-ENG-2025"},"data":{"level":"FULL"}}}],"total":1,"coverage_badge":{"geo":{"scope":"ENGLAND"},"ruleset":{"id":"TIMELINE-2025"},"data":{"level":"FULL"}},"trust_metadata":{"sources":["https://www.gov.uk/government/collections/renters-rights-bill"],"confidence":"high","vintage":"2026-04-18T00:00:00.000Z"},"user_id":null}}}},"500":{"$ref":"#/components/responses/InternalServerError"}}}}}}