{"openapi":"3.1.0","info":{"title":"Basinwise API","version":"1.0.0","description":"Basinwise determines which NPDES stormwater permit governs a construction or industrial site, runs that permit's eligibility screens, and returns the inspection frequency, stabilisation deadlines, required practices and filing path that attach to it, citing the permit section behind every requirement. Where we have not read a jurisdiction's permit we say so and link the agency rather than guessing. The free screening runs in your browser. The same engine is a single-key JSON API and an MCP server, so construction and environmental compliance agents can screen a site mid-task.","contact":{"name":"Basinwise","url":"https://basinwise.vercel.app","email":"hello@basinwise.com"}},"servers":[{"url":"https://basinwise.vercel.app"}],"security":[{},{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"bw_live_*"}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]},"Citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]},"SiteInput":{"type":"object","description":"The site being screened. Sent as a JSON body to /determine, or as query parameters to /requirements.","properties":{"state":{"type":"string","description":"Two-letter state, territory or DC code, e.g. \"CA\"."},"activity":{"type":"string","enum":["construction","industrial"]},"disturbedAcres":{"type":"number","minimum":0,"description":"TOTAL acres the project will disturb over its life, which is what the 1-acre coverage threshold is measured against. `acres` is accepted as an alias."},"acres":{"type":"number","minimum":0,"description":"Alias for disturbedAcres. The parser reads `acres ?? disturbedAcres`, so either name works on either surface."},"maxDisturbedAcresAtOneTime":{"type":["number","null"],"minimum":0,"description":"Greatest acreage disturbed at any one time. A different quantity from disturbedAcres: 2022 CGP Table 2 measures the stabilisation deadline on this, so a project over five acres in total keeps the longer 14-day deadline if it phases the work. Omit or null means not stated, and the determination assumes an unphased site and says so. Rejected if it exceeds disturbedAcres."},"partOfLargerPlan":{"type":"boolean","description":"Part of a larger common plan of development or sale. Defaults to false. The most commonly missed trigger in the permit."},"sectorCode":{"type":["string","null"],"description":"MSGP industrial sector code. Industrial sites only."},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"onTribalLand":{"type":"boolean"},"federalFacility":{"type":"boolean"},"dischargesToImpairedWater":{"type":["boolean","null"],"description":"null means the operator has not checked. Never assumed false: it changes both inspection frequency and the stabilisation deadline."},"dischargesToTier2Water":{"type":["boolean","null"],"description":"null means the operator has not checked."},"aridClimate":{"type":"boolean"}},"required":["state","activity"],"anyOf":[{"required":["disturbedAcres"]},{"required":["acres"]}]},"PermitRef":{"type":"object","description":"The governing permit, or null where we could not identify one.","properties":{"id":{"type":"string"},"name":{"type":"string"},"permitNumber":{"type":["string","null"]},"version":{"type":"string","description":"The permit version this answer was computed against, so an old answer stays defensible."},"authority":{"type":"string"},"agencyName":{"type":"string"},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"effectiveDate":{"type":["string","null"],"format":"date"},"expiryDate":{"type":["string","null"],"format":"date"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["id","name","version","authority","confidence"]},"CredentialGate":{"type":"object","description":"Whether a credentialed preparer is required. \"unknown\" means we have not verified this state and must never be read as \"open\".","properties":{"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"],"description":"null when the trigger is a threshold or plan scope we cannot resolve from the site facts."},"summary":{"type":"string","description":"Plain-language answer, safe to render directly."},"routes":{"type":"array","items":{"type":"string"},"description":"The credentials that qualify in this state."},"stateCourseRequired":{"type":"boolean"},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["gate","summary","routes","confidence"]},"CredentialResult":{"type":"object","properties":{"state":{"type":"string"},"name":{"type":"string"},"acres":{"type":["number","null"]},"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"]},"summary":{"type":"string"},"routes":{"type":"array","items":{"type":"string"}},"stateCourseRequired":{"type":"boolean"},"peStamp":{"type":["object","null"],"description":"Whether a PE stamp is mandated, and what triggers it, where we hold that."},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"note":{"type":["string","null"]},"documentStatus":{"type":"string","description":"The consequence in plain language: whether a generated document is a deliverable or a draft for a credentialed preparer to sign."}},"required":["state","gate","summary","confidence","documentStatus"]},"Jurisdiction":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"npdesAuthorized":{"type":["boolean","null"]},"governingPermitId":{"type":["string","null"]},"permitNumber":{"type":["string","null"]},"permitName":{"type":["string","null"]},"agencyName":{"type":["string","null"]},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"note":{"type":["string","null"],"description":"Why a row is unverified, and which agency to confirm with."},"credential":{"type":"object","description":"Whether a credentialed preparer is required. \"unknown\" means we have not verified this state and must never be read as \"open\".","properties":{"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"],"description":"null when the trigger is a threshold or plan scope we cannot resolve from the site facts."},"summary":{"type":"string","description":"Plain-language answer, safe to render directly."},"routes":{"type":"array","items":{"type":"string"},"description":"The credentials that qualify in this state."},"stateCourseRequired":{"type":"boolean"},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["gate","summary","routes","confidence"]}},"required":["code","name","confidence","credential"]},"JurisdictionList":{"type":"object","properties":{"count":{"type":"integer"},"verifiedCount":{"type":"integer"},"coverageNote":{"type":"string"},"jurisdictions":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"npdesAuthorized":{"type":["boolean","null"]},"governingPermitId":{"type":["string","null"]},"permitNumber":{"type":["string","null"]},"permitName":{"type":["string","null"]},"agencyName":{"type":["string","null"]},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"note":{"type":["string","null"],"description":"Why a row is unverified, and which agency to confirm with."},"credential":{"type":"object","description":"Whether a credentialed preparer is required. \"unknown\" means we have not verified this state and must never be read as \"open\".","properties":{"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"],"description":"null when the trigger is a threshold or plan scope we cannot resolve from the site facts."},"summary":{"type":"string","description":"Plain-language answer, safe to render directly."},"routes":{"type":"array","items":{"type":"string"},"description":"The credentials that qualify in this state."},"stateCourseRequired":{"type":"boolean"},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["gate","summary","routes","confidence"]}},"required":["code","name","confidence","credential"]}}},"required":["count","verifiedCount","jurisdictions"]},"Requirement":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["inspection","stabilization","corrective_action","recordkeeping","filing","monitoring","practice","buffer"]},"label":{"type":"string"},"detail":{"type":"string","description":"The requirement in words, e.g. \"Inspect at least once every 7 calendar days\"."},"value":{"type":["string","number","null"],"description":"The structured value where one exists, e.g. 7 for a seven-day cycle."},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]},"because":{"type":"string","description":"Why this requirement attaches to THIS site rather than in general. What an inspector asks for."}},"required":["id","kind","label","detail","citation"]},"RequirementsResult":{"type":"object","properties":{"site":{"type":"object","description":"The site being screened. Sent as a JSON body to /determine, or as query parameters to /requirements.","properties":{"state":{"type":"string","description":"Two-letter state, territory or DC code, e.g. \"CA\"."},"activity":{"type":"string","enum":["construction","industrial"]},"disturbedAcres":{"type":"number","minimum":0,"description":"TOTAL acres the project will disturb over its life, which is what the 1-acre coverage threshold is measured against. `acres` is accepted as an alias."},"acres":{"type":"number","minimum":0,"description":"Alias for disturbedAcres. The parser reads `acres ?? disturbedAcres`, so either name works on either surface."},"maxDisturbedAcresAtOneTime":{"type":["number","null"],"minimum":0,"description":"Greatest acreage disturbed at any one time. A different quantity from disturbedAcres: 2022 CGP Table 2 measures the stabilisation deadline on this, so a project over five acres in total keeps the longer 14-day deadline if it phases the work. Omit or null means not stated, and the determination assumes an unphased site and says so. Rejected if it exceeds disturbedAcres."},"partOfLargerPlan":{"type":"boolean","description":"Part of a larger common plan of development or sale. Defaults to false. The most commonly missed trigger in the permit."},"sectorCode":{"type":["string","null"],"description":"MSGP industrial sector code. Industrial sites only."},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"onTribalLand":{"type":"boolean"},"federalFacility":{"type":"boolean"},"dischargesToImpairedWater":{"type":["boolean","null"],"description":"null means the operator has not checked. Never assumed false: it changes both inspection frequency and the stabilisation deadline."},"dischargesToTier2Water":{"type":["boolean","null"],"description":"null means the operator has not checked."},"aridClimate":{"type":"boolean"}},"required":["state","activity"],"anyOf":[{"required":["disturbedAcres"]},{"required":["acres"]}]},"coverage":{"type":"string","enum":["required","not_required","verify"]},"coverageReason":{"type":"string"},"permit":{"anyOf":[{"type":"object","description":"The governing permit, or null where we could not identify one.","properties":{"id":{"type":"string"},"name":{"type":"string"},"permitNumber":{"type":["string","null"]},"version":{"type":"string","description":"The permit version this answer was computed against, so an old answer stays defensible."},"authority":{"type":"string"},"agencyName":{"type":"string"},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"effectiveDate":{"type":["string","null"],"format":"date"},"expiryDate":{"type":["string","null"],"format":"date"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["id","name","version","authority","confidence"]},{"type":"null"}]},"requirements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["inspection","stabilization","corrective_action","recordkeeping","filing","monitoring","practice","buffer"]},"label":{"type":"string"},"detail":{"type":"string","description":"The requirement in words, e.g. \"Inspect at least once every 7 calendar days\"."},"value":{"type":["string","number","null"],"description":"The structured value where one exists, e.g. 7 for a seven-day cycle."},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]},"because":{"type":"string","description":"Why this requirement attaches to THIS site rather than in general. What an inspector asks for."}},"required":["id","kind","label","detail","citation"]}},"requirementCount":{"type":"integer"},"eligibilityScreens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"status":{"type":"string","enum":["pass","action_required","ineligible","unknown"],"description":"\"unknown\" means we do not have enough input to say, and we will not guess."},"detail":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["id","label","status","detail","citation"]}},"notices":{"type":"array","items":{"type":"string"},"description":"Surface these VERBATIM. They carry the preparer-credential warning, any coverage gap, and the fact that we do not perform the physical site inspections the permit requires."},"confidence":{"type":"string","enum":["verified","unverified"]},"datasetVersion":{"type":"string"}},"required":["site","coverage","coverageReason","requirements","notices","confidence","datasetVersion"]},"EligibilityScreen":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"status":{"type":"string","enum":["pass","action_required","ineligible","unknown"],"description":"\"unknown\" means we do not have enough input to say, and we will not guess."},"detail":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["id","label","status","detail","citation"]},"DerivationStep":{"type":"object","description":"One step of the reasoning, so every conclusion can be audited.","properties":{"step":{"type":"string"},"result":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["step","result"]},"Determination":{"type":"object","properties":{"coverage":{"type":"string","enum":["required","not_required","verify"],"description":"\"verify\" means we will not answer from what we hold. Industrial sites return it while EPA's MSGP is expired."},"coverageReason":{"type":"string"},"permit":{"anyOf":[{"type":"object","description":"The governing permit, or null where we could not identify one.","properties":{"id":{"type":"string"},"name":{"type":"string"},"permitNumber":{"type":["string","null"]},"version":{"type":"string","description":"The permit version this answer was computed against, so an old answer stays defensible."},"authority":{"type":"string"},"agencyName":{"type":"string"},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"effectiveDate":{"type":["string","null"],"format":"date"},"expiryDate":{"type":["string","null"],"format":"date"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["id","name","version","authority","confidence"]},{"type":"null"}]},"jurisdiction":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"npdesAuthorized":{"type":["boolean","null"]},"governingPermitId":{"type":["string","null"]},"permitNumber":{"type":["string","null"]},"permitName":{"type":["string","null"]},"agencyName":{"type":["string","null"]},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"note":{"type":["string","null"],"description":"Why a row is unverified, and which agency to confirm with."},"credential":{"type":"object","description":"Whether a credentialed preparer is required. \"unknown\" means we have not verified this state and must never be read as \"open\".","properties":{"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"],"description":"null when the trigger is a threshold or plan scope we cannot resolve from the site facts."},"summary":{"type":"string","description":"Plain-language answer, safe to render directly."},"routes":{"type":"array","items":{"type":"string"},"description":"The credentials that qualify in this state."},"stateCourseRequired":{"type":"boolean"},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["gate","summary","routes","confidence"]}},"required":["code","name","confidence","credential"]},"eligibilityScreens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"status":{"type":"string","enum":["pass","action_required","ineligible","unknown"],"description":"\"unknown\" means we do not have enough input to say, and we will not guess."},"detail":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["id","label","status","detail","citation"]}},"requirements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["inspection","stabilization","corrective_action","recordkeeping","filing","monitoring","practice","buffer"]},"label":{"type":"string"},"detail":{"type":"string","description":"The requirement in words, e.g. \"Inspect at least once every 7 calendar days\"."},"value":{"type":["string","number","null"],"description":"The structured value where one exists, e.g. 7 for a seven-day cycle."},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]},"because":{"type":"string","description":"Why this requirement attaches to THIS site rather than in general. What an inspector asks for."}},"required":["id","kind","label","detail","citation"]},"description":"Empty where we have not read the governing permit. That means unknown, NOT that nothing is required; read notices."},"derivation":{"type":"array","items":{"type":"object","description":"One step of the reasoning, so every conclusion can be audited.","properties":{"step":{"type":"string"},"result":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["step","result"]}},"notices":{"type":"array","items":{"type":"string"},"description":"Surface these VERBATIM. They carry the preparer-credential warning, any coverage gap, and the fact that we do not perform the physical site inspections the permit requires."},"confidence":{"type":"string","enum":["verified","unverified"],"description":"Overall data confidence, so a caller can gate on one field rather than walking every citation."},"datasetVersion":{"type":"string","description":"The dataset version this answer was computed against."},"input":{"type":"object","description":"The site being screened. Sent as a JSON body to /determine, or as query parameters to /requirements.","properties":{"state":{"type":"string","description":"Two-letter state, territory or DC code, e.g. \"CA\"."},"activity":{"type":"string","enum":["construction","industrial"]},"disturbedAcres":{"type":"number","minimum":0,"description":"TOTAL acres the project will disturb over its life, which is what the 1-acre coverage threshold is measured against. `acres` is accepted as an alias."},"acres":{"type":"number","minimum":0,"description":"Alias for disturbedAcres. The parser reads `acres ?? disturbedAcres`, so either name works on either surface."},"maxDisturbedAcresAtOneTime":{"type":["number","null"],"minimum":0,"description":"Greatest acreage disturbed at any one time. A different quantity from disturbedAcres: 2022 CGP Table 2 measures the stabilisation deadline on this, so a project over five acres in total keeps the longer 14-day deadline if it phases the work. Omit or null means not stated, and the determination assumes an unphased site and says so. Rejected if it exceeds disturbedAcres."},"partOfLargerPlan":{"type":"boolean","description":"Part of a larger common plan of development or sale. Defaults to false. The most commonly missed trigger in the permit."},"sectorCode":{"type":["string","null"],"description":"MSGP industrial sector code. Industrial sites only."},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"onTribalLand":{"type":"boolean"},"federalFacility":{"type":"boolean"},"dischargesToImpairedWater":{"type":["boolean","null"],"description":"null means the operator has not checked. Never assumed false: it changes both inspection frequency and the stabilisation deadline."},"dischargesToTier2Water":{"type":["boolean","null"],"description":"null means the operator has not checked."},"aridClimate":{"type":"boolean"}},"required":["state","activity"],"anyOf":[{"required":["disturbedAcres"]},{"required":["acres"]}]}},"required":["coverage","coverageReason","jurisdiction","requirements","derivation","notices","confidence","datasetVersion","input"]}}},"paths":{"/api/v1/determine":{"post":{"summary":"Determine which NPDES stormwater permit governs a site and what it requires. Returns the coverage verdict (required, not_required or verify), the governing permit with the version the answer was computed against, the jurisdiction and its permitting authority, that permit's eligibility screens, the requirements that attach to THIS site (each with the permit section it came from and a `because` explaining why it applies here rather than in general), the step-by-step derivation, and a `notices` array you must surface verbatim. Deterministic: no model in the request path, so identical input always returns an identical determination. Requirements are returned ONLY where we hold the governing permit's rules; where we have identified a state permit but not read it, the requirement list is empty and a notice says so rather than substituting the federal permit's numbers. Supports an `Idempotency-Key` header for keyed callers.","operationId":"post_api_v1_determine","security":[{},{"bearerAuth":[]}],"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque caller-chosen key. A keyed caller replaying the same key gets the ORIGINAL stored result back rather than a second billable call. Anonymous callers share no stable identity, so they always recompute and this header is ignored.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}},"X-Quota-Limit":{"description":"Included API calls per month on your plan. Billable callers only.","schema":{"type":"integer"}},"X-Quota-Used":{"description":"Calls used this month. Billable callers only.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Calls left this month. Billable callers only.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"coverage":{"type":"string","enum":["required","not_required","verify"],"description":"\"verify\" means we will not answer from what we hold. Industrial sites return it while EPA's MSGP is expired."},"coverageReason":{"type":"string"},"permit":{"anyOf":[{"type":"object","description":"The governing permit, or null where we could not identify one.","properties":{"id":{"type":"string"},"name":{"type":"string"},"permitNumber":{"type":["string","null"]},"version":{"type":"string","description":"The permit version this answer was computed against, so an old answer stays defensible."},"authority":{"type":"string"},"agencyName":{"type":"string"},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"effectiveDate":{"type":["string","null"],"format":"date"},"expiryDate":{"type":["string","null"],"format":"date"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["id","name","version","authority","confidence"]},{"type":"null"}]},"jurisdiction":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"npdesAuthorized":{"type":["boolean","null"]},"governingPermitId":{"type":["string","null"]},"permitNumber":{"type":["string","null"]},"permitName":{"type":["string","null"]},"agencyName":{"type":["string","null"]},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"note":{"type":["string","null"],"description":"Why a row is unverified, and which agency to confirm with."},"credential":{"type":"object","description":"Whether a credentialed preparer is required. \"unknown\" means we have not verified this state and must never be read as \"open\".","properties":{"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"],"description":"null when the trigger is a threshold or plan scope we cannot resolve from the site facts."},"summary":{"type":"string","description":"Plain-language answer, safe to render directly."},"routes":{"type":"array","items":{"type":"string"},"description":"The credentials that qualify in this state."},"stateCourseRequired":{"type":"boolean"},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["gate","summary","routes","confidence"]}},"required":["code","name","confidence","credential"]},"eligibilityScreens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"status":{"type":"string","enum":["pass","action_required","ineligible","unknown"],"description":"\"unknown\" means we do not have enough input to say, and we will not guess."},"detail":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["id","label","status","detail","citation"]}},"requirements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["inspection","stabilization","corrective_action","recordkeeping","filing","monitoring","practice","buffer"]},"label":{"type":"string"},"detail":{"type":"string","description":"The requirement in words, e.g. \"Inspect at least once every 7 calendar days\"."},"value":{"type":["string","number","null"],"description":"The structured value where one exists, e.g. 7 for a seven-day cycle."},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]},"because":{"type":"string","description":"Why this requirement attaches to THIS site rather than in general. What an inspector asks for."}},"required":["id","kind","label","detail","citation"]},"description":"Empty where we have not read the governing permit. That means unknown, NOT that nothing is required; read notices."},"derivation":{"type":"array","items":{"type":"object","description":"One step of the reasoning, so every conclusion can be audited.","properties":{"step":{"type":"string"},"result":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["step","result"]}},"notices":{"type":"array","items":{"type":"string"},"description":"Surface these VERBATIM. They carry the preparer-credential warning, any coverage gap, and the fact that we do not perform the physical site inspections the permit requires."},"confidence":{"type":"string","enum":["verified","unverified"],"description":"Overall data confidence, so a caller can gate on one field rather than walking every citation."},"datasetVersion":{"type":"string","description":"The dataset version this answer was computed against."},"input":{"type":"object","description":"The site being screened. Sent as a JSON body to /determine, or as query parameters to /requirements.","properties":{"state":{"type":"string","description":"Two-letter state, territory or DC code, e.g. \"CA\"."},"activity":{"type":"string","enum":["construction","industrial"]},"disturbedAcres":{"type":"number","minimum":0,"description":"TOTAL acres the project will disturb over its life, which is what the 1-acre coverage threshold is measured against. `acres` is accepted as an alias."},"acres":{"type":"number","minimum":0,"description":"Alias for disturbedAcres. The parser reads `acres ?? disturbedAcres`, so either name works on either surface."},"maxDisturbedAcresAtOneTime":{"type":["number","null"],"minimum":0,"description":"Greatest acreage disturbed at any one time. A different quantity from disturbedAcres: 2022 CGP Table 2 measures the stabilisation deadline on this, so a project over five acres in total keeps the longer 14-day deadline if it phases the work. Omit or null means not stated, and the determination assumes an unphased site and says so. Rejected if it exceeds disturbedAcres."},"partOfLargerPlan":{"type":"boolean","description":"Part of a larger common plan of development or sale. Defaults to false. The most commonly missed trigger in the permit."},"sectorCode":{"type":["string","null"],"description":"MSGP industrial sector code. Industrial sites only."},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"onTribalLand":{"type":"boolean"},"federalFacility":{"type":"boolean"},"dischargesToImpairedWater":{"type":["boolean","null"],"description":"null means the operator has not checked. Never assumed false: it changes both inspection frequency and the stabilisation deadline."},"dischargesToTier2Water":{"type":["boolean","null"],"description":"null means the operator has not checked."},"aridClimate":{"type":"boolean"}},"required":["state","activity"],"anyOf":[{"required":["disturbedAcres"]},{"required":["acres"]}]}},"required":["coverage","coverageReason","jurisdiction","requirements","derivation","notices","confidence","datasetVersion","input"]},"request_id":{"type":"string"},"disclaimer":{"type":"string"},"attribution":{"type":"string","description":"Present on free/anonymous responses only."}},"required":["data","request_id","disclaimer"]}}}},"400":{"description":"invalid_json: The POST body is not valid JSON. Reported separately from invalid_request so a caller with a broken serialiser is not told its field names are wrong. invalid_request: A required parameter is missing or malformed, an unknown field was sent, or a jurisdiction code we hold no row for was used. The message names the parameter, and details carries known_keys (the fields this endpoint reads) or known_states (the codes we cover), so a caller can correct itself without reading a page.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"401":{"description":"unauthorized: The key you sent is not valid or has been revoked. Only ever returned when you supply a key: a keyless call is allowed at the anonymous rate, never rejected as unauthorized.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"413":{"description":"payload_too_large: The POST body exceeds the byte ceiling. The message names the exact limit.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"429":{"description":"rate_limited: You exceeded the anonymous rate, the sandbox or test-key throttle, your plan's per-minute burst, or your plan's monthly allowance. Retry-After tells you how long to wait.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"500":{"description":"internal: An unexpected server error. Safe to retry; quote the request_id if it persists.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"The site being screened. Sent as a JSON body to /determine, or as query parameters to /requirements.","properties":{"state":{"type":"string","description":"Two-letter state, territory or DC code, e.g. \"CA\"."},"activity":{"type":"string","enum":["construction","industrial"]},"disturbedAcres":{"type":"number","minimum":0,"description":"TOTAL acres the project will disturb over its life, which is what the 1-acre coverage threshold is measured against. `acres` is accepted as an alias."},"acres":{"type":"number","minimum":0,"description":"Alias for disturbedAcres. The parser reads `acres ?? disturbedAcres`, so either name works on either surface."},"maxDisturbedAcresAtOneTime":{"type":["number","null"],"minimum":0,"description":"Greatest acreage disturbed at any one time. A different quantity from disturbedAcres: 2022 CGP Table 2 measures the stabilisation deadline on this, so a project over five acres in total keeps the longer 14-day deadline if it phases the work. Omit or null means not stated, and the determination assumes an unphased site and says so. Rejected if it exceeds disturbedAcres."},"partOfLargerPlan":{"type":"boolean","description":"Part of a larger common plan of development or sale. Defaults to false. The most commonly missed trigger in the permit."},"sectorCode":{"type":["string","null"],"description":"MSGP industrial sector code. Industrial sites only."},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"onTribalLand":{"type":"boolean"},"federalFacility":{"type":"boolean"},"dischargesToImpairedWater":{"type":["boolean","null"],"description":"null means the operator has not checked. Never assumed false: it changes both inspection frequency and the stabilisation deadline."},"dischargesToTier2Water":{"type":["boolean","null"],"description":"null means the operator has not checked."},"aridClimate":{"type":"boolean"}},"required":["state","activity"],"anyOf":[{"required":["disturbedAcres"]},{"required":["acres"]}]}}}}}},"/api/v1/requirements":{"get":{"summary":"The requirements for a site, as a GET so an agent can ask with a URL and nothing else. Same engine and same parser as POST /api/v1/determine, projected down to inspection frequency, stabilisation deadlines, filing deadlines, corrective-action windows, recordkeeping and buffers, each carrying its permit citation. The coverage verdict, the eligibility screens and the notices come with it: a requirement list detached from whether coverage is triggered at all, and from which jurisdictions we have not verified, is a half-answer. An empty requirements array with a notice is the honest response for a state whose permit we have not read.","operationId":"get_api_v1_requirements","security":[{},{"bearerAuth":[]}],"parameters":[{"name":"state","in":"query","required":true,"description":"Two-letter state, territory or DC code, e.g. \"CA\". A code we hold no row for returns invalid_request with details.known_states.","schema":{"type":"string"}},{"name":"activity","in":"query","required":true,"description":"Either \"construction\" or \"industrial\". Required, because the two are governed by different permits and we will not assume one. Industrial returns coverage \"verify\": EPA's Multi-Sector General Permit expired on 28 February 2026 and new operators cannot currently obtain coverage.","schema":{"type":"string"}},{"name":"acres","in":"query","required":true,"description":"TOTAL acres the project will disturb over its life. Decides whether coverage is triggered at all, so there is no default.","schema":{"type":"string"}},{"name":"maxDisturbedAcresAtOneTime","in":"query","required":false,"description":"Greatest acreage disturbed AT ANY ONE TIME. A different quantity from the total, and the one the stabilisation deadline turns on: 2022 CGP Table 2 measures it on land open at once, so a project over five acres in total keeps the longer 14-day deadline if it phases the work. Omit it if you do not know, and the determination assumes an unphased site and says so rather than asserting phasing it was not told about. Rejected if it exceeds the total.","schema":{"type":"string"}},{"name":"partOfLargerPlan","in":"query","required":false,"description":"Whether the project is part of a larger common plan of development or sale. Defaults to false. Pass it explicitly: a half-acre lot inside a 40-acre subdivision IS covered, and this is the single most commonly missed trigger in the permit.","schema":{"type":"string"}},{"name":"dischargesToImpairedWater","in":"query","required":false,"description":"Discharges to a sediment or nutrient impaired water. Omit it and the answer stays honestly unknown: it is never assumed false, because it changes the inspection frequency and the stabilisation deadline.","schema":{"type":"string"}},{"name":"dischargesToTier2Water","in":"query","required":false,"description":"Discharges to a Tier 2, 2.5 or 3 water. Same tri-state handling as dischargesToImpairedWater.","schema":{"type":"string"}},{"name":"aridClimate","in":"query","required":false,"description":"Arid, semi-arid or drought-stricken area, which may allow a reduced inspection frequency during the seasonally dry period.","schema":{"type":"string"}},{"name":"onTribalLand","in":"query","required":false,"description":"EPA retains NPDES authority in Indian country even inside a state that runs its own programme, so this can change which permit governs.","schema":{"type":"string"}},{"name":"federalFacility","in":"query","required":false,"description":"EPA's permit covers federal facilities in some delegated states.","schema":{"type":"string"}},{"name":"sectorCode","in":"query","required":false,"description":"MSGP industrial sector code. Industrial sites only.","schema":{"type":"string"}},{"name":"startDate","in":"query","required":false,"description":"ISO yyyy-mm-dd. Recorded on the determination; it does not change the verdict today.","schema":{"type":"string"}},{"name":"endDate","in":"query","required":false,"description":"ISO yyyy-mm-dd. Recorded on the determination; it does not change the verdict today.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}},"X-Quota-Limit":{"description":"Included API calls per month on your plan. Billable callers only.","schema":{"type":"integer"}},"X-Quota-Used":{"description":"Calls used this month. Billable callers only.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Calls left this month. Billable callers only.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"site":{"type":"object","description":"The site being screened. Sent as a JSON body to /determine, or as query parameters to /requirements.","properties":{"state":{"type":"string","description":"Two-letter state, territory or DC code, e.g. \"CA\"."},"activity":{"type":"string","enum":["construction","industrial"]},"disturbedAcres":{"type":"number","minimum":0,"description":"TOTAL acres the project will disturb over its life, which is what the 1-acre coverage threshold is measured against. `acres` is accepted as an alias."},"acres":{"type":"number","minimum":0,"description":"Alias for disturbedAcres. The parser reads `acres ?? disturbedAcres`, so either name works on either surface."},"maxDisturbedAcresAtOneTime":{"type":["number","null"],"minimum":0,"description":"Greatest acreage disturbed at any one time. A different quantity from disturbedAcres: 2022 CGP Table 2 measures the stabilisation deadline on this, so a project over five acres in total keeps the longer 14-day deadline if it phases the work. Omit or null means not stated, and the determination assumes an unphased site and says so. Rejected if it exceeds disturbedAcres."},"partOfLargerPlan":{"type":"boolean","description":"Part of a larger common plan of development or sale. Defaults to false. The most commonly missed trigger in the permit."},"sectorCode":{"type":["string","null"],"description":"MSGP industrial sector code. Industrial sites only."},"startDate":{"type":["string","null"],"format":"date"},"endDate":{"type":["string","null"],"format":"date"},"onTribalLand":{"type":"boolean"},"federalFacility":{"type":"boolean"},"dischargesToImpairedWater":{"type":["boolean","null"],"description":"null means the operator has not checked. Never assumed false: it changes both inspection frequency and the stabilisation deadline."},"dischargesToTier2Water":{"type":["boolean","null"],"description":"null means the operator has not checked."},"aridClimate":{"type":"boolean"}},"required":["state","activity"],"anyOf":[{"required":["disturbedAcres"]},{"required":["acres"]}]},"coverage":{"type":"string","enum":["required","not_required","verify"]},"coverageReason":{"type":"string"},"permit":{"anyOf":[{"type":"object","description":"The governing permit, or null where we could not identify one.","properties":{"id":{"type":"string"},"name":{"type":"string"},"permitNumber":{"type":["string","null"]},"version":{"type":"string","description":"The permit version this answer was computed against, so an old answer stays defensible."},"authority":{"type":"string"},"agencyName":{"type":"string"},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"effectiveDate":{"type":["string","null"],"format":"date"},"expiryDate":{"type":["string","null"],"format":"date"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["id","name","version","authority","confidence"]},{"type":"null"}]},"requirements":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["inspection","stabilization","corrective_action","recordkeeping","filing","monitoring","practice","buffer"]},"label":{"type":"string"},"detail":{"type":"string","description":"The requirement in words, e.g. \"Inspect at least once every 7 calendar days\"."},"value":{"type":["string","number","null"],"description":"The structured value where one exists, e.g. 7 for a seven-day cycle."},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]},"because":{"type":"string","description":"Why this requirement attaches to THIS site rather than in general. What an inspector asks for."}},"required":["id","kind","label","detail","citation"]}},"requirementCount":{"type":"integer"},"eligibilityScreens":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"status":{"type":"string","enum":["pass","action_required","ineligible","unknown"],"description":"\"unknown\" means we do not have enough input to say, and we will not guess."},"detail":{"type":"string"},"citation":{"type":"object","description":"The permit section one value was read from. confidence \"unverified\" MUST be rendered as Unverified, never as fact. There is deliberately no middle value meaning \"probably\".","properties":{"sourceCitation":{"type":"string","description":"The permit section, e.g. \"2022 CGP Part 4.1.2\". \"Not verified\" where we hold no citation."},"sourceUrl":{"type":"string","format":"uri","description":"The official source document. Government domains only."},"quote":{"type":"string","description":"A short verbatim quote from the permit, proving the clause was read."},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["sourceCitation","sourceUrl","confidence"]}},"required":["id","label","status","detail","citation"]}},"notices":{"type":"array","items":{"type":"string"},"description":"Surface these VERBATIM. They carry the preparer-credential warning, any coverage gap, and the fact that we do not perform the physical site inspections the permit requires."},"confidence":{"type":"string","enum":["verified","unverified"]},"datasetVersion":{"type":"string"}},"required":["site","coverage","coverageReason","requirements","notices","confidence","datasetVersion"]},"request_id":{"type":"string"},"disclaimer":{"type":"string"},"attribution":{"type":"string","description":"Present on free/anonymous responses only."}},"required":["data","request_id","disclaimer"]}}}},"400":{"description":"invalid_request: A required parameter is missing or malformed, an unknown field was sent, or a jurisdiction code we hold no row for was used. The message names the parameter, and details carries known_keys (the fields this endpoint reads) or known_states (the codes we cover), so a caller can correct itself without reading a page.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"401":{"description":"unauthorized: The key you sent is not valid or has been revoked. Only ever returned when you supply a key: a keyless call is allowed at the anonymous rate, never rejected as unauthorized.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"429":{"description":"rate_limited: You exceeded the anonymous rate, the sandbox or test-key throttle, your plan's per-minute burst, or your plan's monthly allowance. Retry-After tells you how long to wait.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"500":{"description":"internal: An unexpected server error. Safe to retry; quote the request_id if it persists.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}}}}},"/api/v1/jurisdictions":{"get":{"summary":"Every state, territory and DC we hold a row for: NPDES authorisation status, the governing permit and its number, the agency name and URL, and the preparer-credential gate that applies there. Unverified jurisdictions are LISTED rather than omitted, each carrying confidence \"unverified\" and a note naming the agency to confirm with: a jurisdiction missing from a coverage list reads as \"no permit applies\", which is never what it means. Free, keyless and not rate-limited.","operationId":"get_api_v1_jurisdictions","security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"count":{"type":"integer"},"verifiedCount":{"type":"integer"},"coverageNote":{"type":"string"},"jurisdictions":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"npdesAuthorized":{"type":["boolean","null"]},"governingPermitId":{"type":["string","null"]},"permitNumber":{"type":["string","null"]},"permitName":{"type":["string","null"]},"agencyName":{"type":["string","null"]},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"note":{"type":["string","null"],"description":"Why a row is unverified, and which agency to confirm with."},"credential":{"type":"object","description":"Whether a credentialed preparer is required. \"unknown\" means we have not verified this state and must never be read as \"open\".","properties":{"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"],"description":"null when the trigger is a threshold or plan scope we cannot resolve from the site facts."},"summary":{"type":"string","description":"Plain-language answer, safe to render directly."},"routes":{"type":"array","items":{"type":"string"},"description":"The credentials that qualify in this state."},"stateCourseRequired":{"type":"boolean"},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["gate","summary","routes","confidence"]}},"required":["code","name","confidence","credential"]}}},"required":["count","verifiedCount","jurisdictions"]},"request_id":{"type":"string"},"disclaimer":{"type":"string"},"attribution":{"type":"string","description":"Present on free/anonymous responses only."}},"required":["data","request_id","disclaimer"]}}}},"401":{"description":"unauthorized: The key you sent is not valid or has been revoked. Only ever returned when you supply a key: a keyless call is allowed at the anonymous rate, never rejected as unauthorized.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"500":{"description":"internal: An unexpected server error. Safe to retry; quote the request_id if it persists.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}}}}},"/api/v1/jurisdictions/{code}":{"get":{"summary":"One jurisdiction: who permits (the state or EPA), the governing permit and number, the agency links, and the preparer-credential gate. A code we hold no row for returns invalid_request with details.known_states so a caller can correct itself; a code we hold but have not verified returns 200 with confidence \"unverified\" and the agency to confirm with. Free, keyless and not rate-limited.","operationId":"get_api_v1_jurisdictions_code","security":[{},{"bearerAuth":[]}],"parameters":[{"name":"code","in":"path","required":true,"description":"Two-letter jurisdiction code, e.g. \"CA\". Case-insensitive.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"npdesAuthorized":{"type":["boolean","null"]},"governingPermitId":{"type":["string","null"]},"permitNumber":{"type":["string","null"]},"permitName":{"type":["string","null"]},"agencyName":{"type":["string","null"]},"agencyUrl":{"type":["string","null"],"format":"uri"},"permitUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"note":{"type":["string","null"],"description":"Why a row is unverified, and which agency to confirm with."},"credential":{"type":"object","description":"Whether a credentialed preparer is required. \"unknown\" means we have not verified this state and must never be read as \"open\".","properties":{"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"],"description":"null when the trigger is a threshold or plan scope we cannot resolve from the site facts."},"summary":{"type":"string","description":"Plain-language answer, safe to render directly."},"routes":{"type":"array","items":{"type":"string"},"description":"The credentials that qualify in this state."},"stateCourseRequired":{"type":"boolean"},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]}},"required":["gate","summary","routes","confidence"]}},"required":["code","name","confidence","credential"]},"request_id":{"type":"string"},"disclaimer":{"type":"string"},"attribution":{"type":"string","description":"Present on free/anonymous responses only."}},"required":["data","request_id","disclaimer"]}}}},"400":{"description":"invalid_request: A required parameter is missing or malformed, an unknown field was sent, or a jurisdiction code we hold no row for was used. The message names the parameter, and details carries known_keys (the fields this endpoint reads) or known_states (the codes we cover), so a caller can correct itself without reading a page.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"401":{"description":"unauthorized: The key you sent is not valid or has been revoked. Only ever returned when you supply a key: a keyless call is allowed at the anonymous rate, never rejected as unauthorized.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"500":{"description":"internal: An unexpected server error. Safe to retry; quote the request_id if it persists.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}}}}},"/api/v1/credentials":{"get":{"summary":"Does this state require a credentialed preparer to prepare or sign the stormwater plan, and does the requirement bite for a site of this size? This is the question that decides whether a generated document is the operator's deliverable or a draft somebody else has to sign, so it gets an endpoint of its own. The answer is a structured gate (open, gated, conditional or unknown) rather than a boolean, because states differ on three independent axes: which credentials qualify, whether a state course is layered on top, and what triggers the gate (acreage in Utah and Oregon, plan scope in New York). A state we have not verified returns \"unknown\", never \"open\": defaulting an unverified state to open would be the most dangerous answer this product could give. `documentStatus` states the consequence in plain language on every response.","operationId":"get_api_v1_credentials","security":[{},{"bearerAuth":[]}],"parameters":[{"name":"state","in":"query","required":true,"description":"Two-letter state code, e.g. \"CA\".","schema":{"type":"string"}},{"name":"acres","in":"query","required":false,"description":"Acres disturbed. Optional, and it matters: several states gate only above an acreage threshold. Without it, a conditional state answers appliesToThisSite: null and names the threshold that decides it rather than guessing.","schema":{"type":"string"}}],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}},"X-Quota-Limit":{"description":"Included API calls per month on your plan. Billable callers only.","schema":{"type":"integer"}},"X-Quota-Used":{"description":"Calls used this month. Billable callers only.","schema":{"type":"integer"}},"X-Quota-Remaining":{"description":"Calls left this month. Billable callers only.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"state":{"type":"string"},"name":{"type":"string"},"acres":{"type":["number","null"]},"gate":{"type":"string","enum":["open","gated","conditional","unknown"]},"appliesToThisSite":{"type":["boolean","null"]},"summary":{"type":"string"},"routes":{"type":"array","items":{"type":"string"}},"stateCourseRequired":{"type":"boolean"},"peStamp":{"type":["object","null"],"description":"Whether a PE stamp is mandated, and what triggers it, where we hold that."},"sourceCitation":{"type":["string","null"]},"sourceUrl":{"type":["string","null"],"format":"uri"},"confidence":{"type":"string","enum":["verified","unverified"]},"note":{"type":["string","null"]},"documentStatus":{"type":"string","description":"The consequence in plain language: whether a generated document is a deliverable or a draft for a credentialed preparer to sign."}},"required":["state","gate","summary","confidence","documentStatus"]},"request_id":{"type":"string"},"disclaimer":{"type":"string"},"attribution":{"type":"string","description":"Present on free/anonymous responses only."}},"required":["data","request_id","disclaimer"]}}}},"400":{"description":"invalid_request: A required parameter is missing or malformed, an unknown field was sent, or a jurisdiction code we hold no row for was used. The message names the parameter, and details carries known_keys (the fields this endpoint reads) or known_states (the codes we cover), so a caller can correct itself without reading a page.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"401":{"description":"unauthorized: The key you sent is not valid or has been revoked. Only ever returned when you supply a key: a keyless call is allowed at the anonymous rate, never rejected as unauthorized.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"429":{"description":"rate_limited: You exceeded the anonymous rate, the sandbox or test-key throttle, your plan's per-minute burst, or your plan's monthly allowance. Retry-After tells you how long to wait.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}},"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"500":{"description":"internal: An unexpected server error. Safe to retry; quote the request_id if it persists.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}}}}},"/api/v1/pricing":{"get":{"summary":"Machine-readable pricing: every plan id, its monthly price (read live from lib/plans.ts, never hardcoded), what it includes, the included monthly API-call allowance (a hard ceiling, not a meter), rate limits, and the public sandbox key. Lets an agent self-select a plan without a human reading the pricing page. Free, keyless, not rate-limited.","operationId":"get_api_v1_pricing","security":[{},{"bearerAuth":[]}],"parameters":[],"responses":{"200":{"description":"Success","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"currency":{"type":"string"},"unit":{"type":"string"},"determinism":{"type":"string"},"anonymous":{"type":"object","properties":{"price_usd":{"type":"number"},"rate_limit_per_minute":{"type":"integer"},"rate_limit_per_day":{"type":"integer"},"api_access":{"type":"boolean"},"note":{"type":"string"}}},"sandbox_key":{"type":"object","properties":{"key":{"type":"string","description":"A real, public key that works with no signup."},"rate_limit_per_minute":{"type":"integer"},"rate_limit_per_day":{"type":"integer"},"bills":{"type":"boolean"},"note":{"type":"string"}}},"test_key":{"type":"object","properties":{"rate_limit_per_minute":{"type":"integer"},"rate_limit_per_day":{"type":"integer"},"bills":{"type":"boolean"},"note":{"type":"string"}}},"plans":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","enum":["free","pro","scale"]},"name":{"type":"string"},"price_usd_per_month":{"type":"number"},"cadence":{"type":"string"},"tagline":{"type":"string"},"included_api_calls_per_month":{"type":"integer"},"rate_limit_per_minute":{"type":"integer"},"saved_sites":{"description":"An integer, or the string \"unlimited\"."},"seats":{"type":"integer"},"api_access":{"type":"boolean"},"site_history":{"type":"boolean"},"swppp_document":{"type":"boolean"},"inspection_log":{"type":"boolean"},"exports":{"type":"boolean"},"priority_support":{"type":"boolean"},"features":{"type":"array","items":{"type":"string"}}}}},"checkout":{"type":"object","properties":{"note":{"type":"string"},"upgrade_url":{"type":"string","format":"uri"}}}},"required":["currency","unit","anonymous","plans"]},"request_id":{"type":"string"},"disclaimer":{"type":"string"},"attribution":{"type":"string","description":"Present on free/anonymous responses only."}},"required":["data","request_id","disclaimer"]}}}},"401":{"description":"unauthorized: The key you sent is not valid or has been revoked. Only ever returned when you supply a key: a keyless call is allowed at the anonymous rate, never rejected as unauthorized.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}},"500":{"description":"internal: An unexpected server error. Safe to retry; quote the request_id if it persists.","headers":{"X-Request-Id":{"description":"Correlation id for this request. Quote it in a support question. Echoed from a supplied x-request-id header when you send one.","schema":{"type":"string"}},"X-RateLimit-Limit":{"description":"Requests allowed in the current window for your tier.","schema":{"type":"integer"}},"X-RateLimit-Remaining":{"description":"Requests left in the current window.","schema":{"type":"integer"}},"X-RateLimit-Reset":{"description":"Unix seconds at which the current window resets.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["invalid_request","invalid_json","unauthorized","not_found","method_not_allowed","payload_too_large","rate_limited","internal"]},"message":{"type":"string"},"details":{"type":"object","description":"Extra context where a handler supplies it. An unknown field carries known_keys (the fields this endpoint reads) and unknown_keys; an unknown jurisdiction carries known_states; a 429 carries upgrade_url.","properties":{"known_keys":{"type":"array","items":{"type":"string"}},"unknown_keys":{"type":"array","items":{"type":"string"}},"known_states":{"type":"array","items":{"type":"string"}},"known_values":{"type":"array","items":{"type":"string"}}}}},"required":["code","message"]},"request_id":{"type":"string"}},"required":["error"]}}}}}}}}}