{"openapi":"3.1.0","info":{"title":"Tahadhari Partner API","version":"1.0.0","summary":"Incidents, credibility and multi-agency response for flood early warning in Mandera County, Kenya.","description":"The Partner API lets humanitarian and government partners read incidents in their operating areas (with a transparent credibility score), submit reports from their own systems, add evidence, and coordinate their response with the county.\n\n**Authentication:** send your key as `Authorization: Bearer th_live_…`. Keys are issued by your partner coordinator in the Tahadhari partner portal, or by the county EOC. Each key belongs to one organisation and carries scopes.\n\n**Rate limit:** 120 requests per minute per key. Over the limit you get `429`; wait a minute and retry.\n\n**Errors:** every error is JSON `{ \"error\": \"<plain-language message>\" }` with a 4xx/5xx status.\n\n**Privacy:** the API never returns citizen phone numbers, reporter ids, report text, photos or reporters’ track records — only aggregates (report counts, channels, distinct reporters, the credibility breakdown).\n\n**Timestamps** are ISO 8601 in UTC. **Lists** use keyset pagination: pass `nextCursor` back as `cursor` until it is `null`.\n\nHuman-readable guide: https://elnino.medicdecode.com/developers","contact":{"name":"Mandera County EOC — Tahadhari","url":"https://elnino.medicdecode.com/developers"}},"servers":[{"url":"https://elnino.medicdecode.com/api/partner/v1","description":"This server"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Account","description":"Who the key belongs to."},{"name":"Incidents","description":"Incidents with credibility, responses and discussion."},{"name":"Response","description":"Offer and update your organisation’s response."},{"name":"Evidence","description":"Confirmations, news links and comments."},{"name":"Reports","description":"Submit reports from your own systems."},{"name":"Alerts","description":"Public early-warning alerts."},{"name":"Organisations","description":"Who operates where."}],"paths":{"/openapi.json":{"get":{"tags":["Account"],"operationId":"getOpenApi","summary":"This document","description":"No key needed.","security":[],"responses":{"200":{"description":"OpenAPI 3.1 document.","content":{"application/json":{"schema":{"type":"object"}}}}}}},"/me":{"get":{"tags":["Account"],"operationId":"getMe","summary":"Your organisation, scopes and operating areas","description":"**Scope:** any valid key.","responses":{"200":{"description":"The key’s organisation, scopes, operating areas and covered wards.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/incidents":{"get":{"tags":["Incidents"],"operationId":"listIncidents","summary":"List incidents","description":"**Scope:** `incidents:read` — Read incidents in your organisation's areas (with credibility and responses) for `scope=area` (your organisation's operating areas).\n\n**Scope:** `incidents:read_all` — Read incidents in every ward for `scope=all` (every ward).\n\nOrdered by `updatedAt` descending. Poll with `since` set to the time of your last sync to get only what changed.","parameters":[{"name":"scope","in":"query","schema":{"type":"string","enum":["area","all"],"default":"area"},"description":"`area`: your operating areas. `all`: every ward (needs `incidents:read_all`)."},{"name":"status","in":"query","schema":{"type":"string","description":"Comma-separated."},"example":"open,verified,responding","description":"Comma-separated incident statuses: open, verified, responding, resolved, dismissed."},{"name":"verification","in":"query","schema":{"type":"string","description":"Comma-separated."},"example":"corroborated,confirmed","description":"Comma-separated verification levels: single_source, corroborated, confirmed, disputed, false."},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"example":"2026-09-23T06:00:00Z","description":"Only incidents updated at or after this time."},{"name":"ward","in":"query","schema":{"type":"string"},"example":"neboi","description":"One ward id. With `scope=area` it must be one of your wards."},{"$ref":"#/components/parameters/limit"},{"$ref":"#/components/parameters/cursor"}],"responses":{"200":{"description":"A page of incidents.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Incident"}},"nextCursor":{"anyOf":[{"type":"string","description":"Pass as `cursor` to get the next page."},{"type":"null"}]},"scope":{"type":"string","enum":["area","all"]},"note":{"type":"string","description":"Present when your organisation has no operating areas yet."}},"required":["data","nextCursor","scope"]},"example":{"data":[{"id":"in-01","title":"Houses flooded near Neboi market, families on rooftops","ward":{"id":"neboi","name":"Neboi"},"subCounty":{"id":"mandera-east","name":"Mandera East"},"category":"house_flooded","categoryLabel":"House flooded","severity":"life_threatening","status":"responding","lat":3.9312,"lng":41.8611,"createdAt":"2026-09-23T10:02:11.000Z","updatedAt":"2026-09-23T12:49:12.787Z","resolvedAt":null,"credibility":{"verification":"confirmed","label":"Confirmed","explain":"Checked on the ground by a named official or field officer.","confidence":86,"distinctReporters":3,"breakdown":[{"label":"3 independent reporters","points":36},{"label":"3 different channels","points":6},{"label":"GPS location","points":4},{"label":"Confirmed on the ground by an official","points":40}],"warning":null},"publicStatus":"published","publicNote":null,"leadOrg":{"id":"krcs","name":"Kenya Red Cross (Mandera branch)"},"responses":[{"org":{"id":"krcs","name":"Kenya Red Cross (Mandera branch)"},"status":"lead","interventions":["rescue_boat","first_aid"]},{"org":{"id":"wash-a","name":"WASH Partner A"},"status":"offered","interventions":["water_trucking","chlorination"]}],"reportCount":3,"channels":["app","sms","whatsapp"]}],"nextCursor":"MjAyNi0wOS0yMyAxMjo0OToxMi43ODcrMDB8aW4tMDE","scope":"area"}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/incidents/{id}":{"get":{"tags":["Incidents"],"operationId":"getIncident","summary":"One incident with evidence, responses and discussion","description":"**Scope:** `incidents:read` — Read incidents in your organisation's areas (with credibility and responses)\n\nVisible when the incident is in your operating areas, when your key also has `incidents:read_all`, or when your organisation has responded to it. Otherwise `404`.","parameters":[{"$ref":"#/components/parameters/incidentId"}],"responses":{"200":{"description":"The incident.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/IncidentDetail"}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/incidents/{id}/responses":{"post":{"tags":["Response"],"operationId":"offerResponse","summary":"Offer (or update) your organisation’s response","description":"**Scope:** `responses:write` — Offer and update your organisation's responses\n\nCreates an offer with status `offered`; the county then names a lead agency, marks others as supporting, or declines. Sending again updates your offer (and re-opens it if it was withdrawn or declined). Interventions another engaged organisation already covers are flagged in `overlaps` on the incident.","parameters":[{"$ref":"#/components/parameters/incidentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OfferInput"},"example":{"interventions":["water_trucking","chlorination"],"description":"Two bowsers from Mandera town depot","resources":"2 × 10,000 L bowsers, 4 staff","etaMinutes":90,"proposeLead":false}}}},"responses":{"201":{"description":"The offer as stored.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Response"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/responses/{id}":{"patch":{"tags":["Response"],"operationId":"updateResponse","summary":"Update your response status","description":"**Scope:** `responses:write` — Offer and update your organisation's responses\n\nOnly your own organisation's responses. `on_site` and `completed` need the county to have accepted the offer first (`lead` or `supporting`), otherwise `409`. `withdrawn` is always allowed.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"rs-8k2j1x"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResponseStatusInput"},"example":{"status":"on_site","note":"Bowsers at Neboi primary school"}}}},"responses":{"200":{"description":"The updated response.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Response"}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"409":{"$ref":"#/components/responses/E409"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/incidents/{id}/evidence":{"post":{"tags":["Evidence"],"operationId":"addEvidence","summary":"Add evidence","description":"**Scope:** `evidence:write` — Add evidence (e.g. field confirmation, news links) and comments\n\n`partner` (your own field staff confirm — or, with `supports: false`, contradict — the incident) counts immediately and adds up to 15 credibility points. `media` and `other` are stored as suggestions and count once a county reviewer accepts them.","parameters":[{"$ref":"#/components/parameters/incidentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EvidenceInput"},"example":{"kind":"partner","title":"Our WASH officer confirms 40 households displaced","note":"Seen at 11:20, water knee deep","supports":true}}}},"responses":{"201":{"description":"Stored.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"incidentId":{"type":"string"},"status":{"type":"string","enum":["accepted","suggested"]},"message":{"type":"string"},"credibility":{"anyOf":[{"$ref":"#/components/schemas/Credibility"},{"type":"null"}]}},"required":["incidentId","status","message","credibility"]}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/incidents/{id}/notes":{"post":{"tags":["Evidence"],"operationId":"addNote","summary":"Post to the discussion thread","description":"**Scope:** `evidence:write` — Add evidence (e.g. field confirmation, news links) and comments\n\nThe message appears under the name of the person who created the key, with your organisation, marked \"(via API)\".","parameters":[{"$ref":"#/components/parameters/incidentId"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","description":"2–1000 characters.","minLength":2,"maxLength":1000}},"required":["body"]},"example":{"body":"Our team can reach Neboi by 14:00 if the Rhamu road is open."}}}},"responses":{"201":{"description":"Posted.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"incidentId":{"type":"string"},"body":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["incidentId","body","at"]}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"404":{"$ref":"#/components/responses/E404"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/reports":{"post":{"tags":["Reports"],"operationId":"submitReport","summary":"Submit a report","description":"**Scope:** `reports:write` — Submit reports from your systems (Kobo, ODK, call centres)\n\nThe report goes through the same intake as SMS, WhatsApp and the app (channel `partner_api`): it is placed by GPS (or ward centre), triaged, grouped with open incidents of the same category within 1.5 km and 12 hours, scored for credibility and sent to responders. Give `wardId` or both `lat` and `lng`; GPS wins when both are given.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReportInput"},"example":{"kind":"hazard","text":"Bridge on the Rhamu road partly submerged, foot traffic only","lang":"en","lat":3.9331,"lng":41.2144,"placeName":"Rhamu bridge","category":"infrastructure","externalId":"kobo-58213"}}}},"responses":{"201":{"description":"Report received.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ReportResult"}},"required":["data"]},"example":{"data":{"ref":"MDR-4532","reportId":"rp-x81k2","incidentId":"in-h9s1","grouped":false,"ward":{"id":"rhamu","name":"Rhamu"},"category":"infrastructure","severity":"moderate","credibility":{"verification":"single_source","label":"Unverified: one report","explain":"Only one person has reported this. It has not been checked.","confidence":16,"distinctReporters":1,"breakdown":[{"label":"1 reporter","points":12},{"label":"GPS location","points":4}],"warning":"Not verified. Only one person has reported this so far."},"externalId":"kobo-58213"}}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/alerts":{"get":{"tags":["Alerts"],"operationId":"listAlerts","summary":"Active alerts","description":"**Scope:** `alerts:read` — Read public alerts\n\nAlerts that are sent and not expired, most severe first. Text is in English (`en`), Kiswahili (`sw`) and Somali (`so`). The same alerts are published as CAP 1.2 at `/api/cap/alerts.xml`.","parameters":[{"name":"ward","in":"query","schema":{"type":"string"},"example":"township","description":"Only alerts covering this ward."}],"responses":{"200":{"description":"Active alerts.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Alert"}}},"required":["data"]}}}},"400":{"$ref":"#/components/responses/E400"},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}},"/organisations":{"get":{"tags":["Organisations"],"operationId":"listOrganisations","summary":"Who operates where","description":"**Scope:** any valid key.\n\nEvery organisation with its services, operating areas, the wards those cover and the number of field officers per ward. Counts only: no staff names.","parameters":[{"name":"ward","in":"query","schema":{"type":"string"},"example":"neboi","description":"Only organisations operating in this ward."}],"responses":{"200":{"description":"The directory.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Organisation"}}},"required":["data"]}}}},"401":{"$ref":"#/components/responses/E401"},"403":{"$ref":"#/components/responses/E403"},"429":{"$ref":"#/components/responses/E429"},"500":{"$ref":"#/components/responses/E500"}}}}},"webhooks":{"incident.created":{"post":{"operationId":"webhook_incident_created","summary":"A new incident opens in your areas","description":"`data.incidentId` is always present; the other fields depend on what changed, so fetch `GET /incidents/{id}` for the full picture. Sent to every active subscription of an organisation whose operating area covers the ward concerned. Verify `X-Tahadhari-Signature` before trusting the body. A subscription is paused after 20 consecutive failed deliveries (non-2xx or no answer within 8 s); re-enable it in the partner portal.","parameters":[{"name":"X-Tahadhari-Event","in":"header","required":true,"schema":{"type":"string","enum":["incident.created"]}},{"name":"X-Tahadhari-Signature","in":"header","required":true,"schema":{"type":"string","description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your webhook secret>`"},"example":"t=1790157600,v1=5f2b0c…"},{"name":"User-Agent","in":"header","schema":{"type":"string","example":"Tahadhari-Webhooks/1"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"},"example":{"id":"evt_3f9a61c2b0d4e8a7","event":"incident.created","created":"2026-09-23T10:02:14.120Z","data":{"incidentId":"in-h9s1","wardId":"neboi","category":"house_flooded","severity":"severe","verification":"single_source","confidence":18,"reports":1}}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Reply quickly (within 8 s) and do slow work afterwards."}}}},"incident.updated":{"post":{"operationId":"webhook_incident_updated","summary":"Status, credibility or publication changes","description":"`data.incidentId` is always present; the other fields depend on what changed, so fetch `GET /incidents/{id}` for the full picture. Sent to every active subscription of an organisation whose operating area covers the ward concerned. Verify `X-Tahadhari-Signature` before trusting the body. A subscription is paused after 20 consecutive failed deliveries (non-2xx or no answer within 8 s); re-enable it in the partner portal.","parameters":[{"name":"X-Tahadhari-Event","in":"header","required":true,"schema":{"type":"string","enum":["incident.updated"]}},{"name":"X-Tahadhari-Signature","in":"header","required":true,"schema":{"type":"string","description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your webhook secret>`"},"example":"t=1790157600,v1=5f2b0c…"},{"name":"User-Agent","in":"header","schema":{"type":"string","example":"Tahadhari-Webhooks/1"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"},"example":{"id":"evt_3f9a61c2b0d4e8a7","event":"incident.updated","created":"2026-09-23T10:02:14.120Z","data":{"incidentId":"in-01","verification":"corroborated","confidence":54}}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Reply quickly (within 8 s) and do slow work afterwards."}}}},"incident.response":{"post":{"operationId":"webhook_incident_response","summary":"Responses offered, coordinated or updated","description":"`data.incidentId` is always present; the other fields depend on what changed, so fetch `GET /incidents/{id}` for the full picture. Sent to every active subscription of an organisation whose operating area covers the ward concerned. Verify `X-Tahadhari-Signature` before trusting the body. A subscription is paused after 20 consecutive failed deliveries (non-2xx or no answer within 8 s); re-enable it in the partner portal.","parameters":[{"name":"X-Tahadhari-Event","in":"header","required":true,"schema":{"type":"string","enum":["incident.response"]}},{"name":"X-Tahadhari-Signature","in":"header","required":true,"schema":{"type":"string","description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your webhook secret>`"},"example":"t=1790157600,v1=5f2b0c…"},{"name":"User-Agent","in":"header","schema":{"type":"string","example":"Tahadhari-Webhooks/1"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"},"example":{"id":"evt_3f9a61c2b0d4e8a7","event":"incident.response","created":"2026-09-23T10:02:14.120Z","data":{"incidentId":"in-01","orgId":"krcs","status":"offered","interventions":["rescue_boat","first_aid"]}}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Reply quickly (within 8 s) and do slow work afterwards."}}}},"alert.sent":{"post":{"operationId":"webhook_alert_sent","summary":"An alert is released","description":"`data` carries the alert id, hazard, level, wards, trilingual title/body/actions, expiry and estimated reach. Sent to every active subscription of an organisation whose operating area covers the ward concerned. Verify `X-Tahadhari-Signature` before trusting the body. A subscription is paused after 20 consecutive failed deliveries (non-2xx or no answer within 8 s); re-enable it in the partner portal.","parameters":[{"name":"X-Tahadhari-Event","in":"header","required":true,"schema":{"type":"string","enum":["alert.sent"]}},{"name":"X-Tahadhari-Signature","in":"header","required":true,"schema":{"type":"string","description":"`t=<unix seconds>,v1=<hex HMAC-SHA256 of \"<t>.<raw body>\" with your webhook secret>`"},"example":"t=1790157600,v1=5f2b0c…"},{"name":"User-Agent","in":"header","schema":{"type":"string","example":"Tahadhari-Webhooks/1"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookEnvelope"},"example":{"id":"evt_3f9a61c2b0d4e8a7","event":"alert.sent","created":"2026-09-23T10:02:14.120Z","data":{"alertId":"al-001","level":3,"hazard":"flood","wardIds":["township","neboi"]}}}}},"responses":{"2XX":{"description":"Any 2xx acknowledges the delivery. Reply quickly (within 8 s) and do slow work afterwards."}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"th_live_<prefix>_<secret>","description":"Partner API key. Scopes per operation are listed in each description."}},"parameters":{"incidentId":{"name":"id","in":"path","required":true,"schema":{"type":"string"},"example":"in-01"},"limit":{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},"cursor":{"name":"cursor","in":"query","schema":{"type":"string","description":"Opaque. The `nextCursor` from the previous page."}}},"responses":{"E400":{"description":"The request is not valid. The message names the field and the problem.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"status: use one or more of: open, verified, responding, resolved, dismissed"}}}},"E401":{"description":"No key, or the key is not valid or has been revoked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"This API key is not valid or has been revoked."}}}},"E403":{"description":"The key does not have the scope this needs, or the ward is outside your areas.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"This key does not have the \"responses:write\" scope."}}}},"E404":{"description":"Not found, or outside what the key may see.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Incident \"in-99\" was not found, or it is outside the areas this key can see."}}}},"E409":{"description":"The action does not fit the current state (for example the incident is closed).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"This incident is closed."}}}},"E429":{"description":"More than 120 requests in a minute from this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Too many requests. The limit is 120 per minute per key."}}}},"E500":{"description":"Something went wrong on our side.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Something went wrong on our side. Try again."}}}}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"Plain-language description of the problem."}},"required":["error"]},"Ref":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"Me":{"type":"object","properties":{"organisation":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"anyOf":[{"type":"string","enum":["government","red_cross","un","ngo","private"]},{"type":"null"}]}},"required":["id","name","kind"]},"key":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string","description":"The visible start of the key, e.g. `th_live_bfd7a2ce`."},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id"]},"scopes":{"type":"array","items":{"type":"object","properties":{"scope":{"type":"string","enum":["incidents:read","incidents:read_all","reports:write","responses:write","evidence:write","alerts:read"]},"description":{"type":"string"}},"required":["scope","description"]}},"operatingAreas":{"type":"array","items":{"$ref":"#/components/schemas/AreaRef"}},"wards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"subCounty":{"anyOf":[{"$ref":"#/components/schemas/Ref"},{"type":"null"}]}},"required":["id","name","subCounty"]},"description":"Every ward covered by the operating areas."}},"required":["organisation","key","scopes","operatingAreas","wards"]},"AreaRef":{"type":"object","properties":{"scope":{"type":"string","enum":["ward","sub_county","county"]},"id":{"type":"string"},"name":{"type":"string"}},"required":["scope","id","name"]},"Credibility":{"type":"object","properties":{"verification":{"type":"string","enum":["single_source","corroborated","confirmed","disputed","false"]},"label":{"type":"string","description":"Short human label, e.g. \"Corroborated\"."},"explain":{"type":"string","description":"One sentence on what the level means."},"confidence":{"type":"integer","minimum":0,"maximum":100},"distinctReporters":{"type":"integer","minimum":0},"breakdown":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"},"points":{"type":"integer"}},"required":["label","points"]},"description":"Named contributions that add up to the confidence score."},"warning":{"anyOf":[{"type":"string","description":"The warning shown to the public next to anything not confirmed."},{"type":"null"}]}},"required":["verification","label","explain","confidence","distinctReporters","breakdown","warning"],"description":"How far the incident can be trusted, and why."},"ResponseSummary":{"type":"object","properties":{"org":{"$ref":"#/components/schemas/Ref"},"status":{"type":"string","enum":["offered","lead","supporting","on_site","completed","withdrawn","declined"]},"interventions":{"type":"array","items":{"$ref":"#/components/schemas/InterventionId"}}},"required":["org","status","interventions"]},"InterventionId":{"type":"string","description":"`search_rescue`: Search and rescue; `rescue_boat`: Boat rescue; `evacuation`: Evacuation / transport; `first_aid`: First aid; `medical_team`: Medical team; `ambulance`: Ambulance / referral; `water_trucking`: Water trucking; `chlorination`: Water treatment / chlorination; `latrines`: Latrines and hygiene; `shelter`: Tents and shelter; `nfi`: Household kits (NFIs); `food`: Food rations / hot meals; `cash`: Cash transfers; `livestock`: Livestock rescue / feed; `road_clearing`: Road clearing / repair; `psychosocial`: Psychosocial support; `assessment`: Needs assessment","enum":["search_rescue","rescue_boat","evacuation","first_aid","medical_team","ambulance","water_trucking","chlorination","latrines","shelter","nfi","food","cash","livestock","road_clearing","psychosocial","assessment"]},"Incident":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"ward":{"$ref":"#/components/schemas/Ref"},"subCounty":{"anyOf":[{"$ref":"#/components/schemas/Ref"},{"type":"null"}]},"category":{"type":"string","enum":["road_cut","house_flooded","people_stranded","livestock","water_sanitation","health","infrastructure","rumour","other"]},"categoryLabel":{"type":"string"},"severity":{"type":"string","enum":["minor","moderate","severe","life_threatening"]},"status":{"type":"string","enum":["open","verified","responding","resolved","dismissed"]},"lat":{"type":"number"},"lng":{"type":"number"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"resolvedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"credibility":{"$ref":"#/components/schemas/Credibility"},"publicStatus":{"type":"string","description":"`hidden`: responders, county and partners only. `published_with_warning`: public with a \"not verified\" warning. `published`: public as confirmed.","enum":["hidden","published_with_warning","published"]},"publicNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"leadOrg":{"anyOf":[{"$ref":"#/components/schemas/Ref"},{"type":"null"}]},"reportCount":{"type":"integer"},"channels":{"type":"array","items":{"type":"string","enum":["app","web","whatsapp","sms","ussd","voice","responder","partner_api"]},"description":"Distinct channels the reports came through."},"responses":{"type":"array","items":{"$ref":"#/components/schemas/ResponseSummary"}}},"required":["id","title","ward","subCounty","category","categoryLabel","severity","status","lat","lng","createdAt","updatedAt","resolvedAt","credibility","publicStatus","publicNote","leadOrg","reportCount","channels","responses"]},"IncidentDetail":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"ward":{"$ref":"#/components/schemas/Ref"},"subCounty":{"anyOf":[{"$ref":"#/components/schemas/Ref"},{"type":"null"}]},"category":{"type":"string","enum":["road_cut","house_flooded","people_stranded","livestock","water_sanitation","health","infrastructure","rumour","other"]},"categoryLabel":{"type":"string"},"severity":{"type":"string","enum":["minor","moderate","severe","life_threatening"]},"status":{"type":"string","enum":["open","verified","responding","resolved","dismissed"]},"lat":{"type":"number"},"lng":{"type":"number"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"resolvedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"credibility":{"$ref":"#/components/schemas/Credibility"},"publicStatus":{"type":"string","description":"`hidden`: responders, county and partners only. `published_with_warning`: public with a \"not verified\" warning. `published`: public as confirmed.","enum":["hidden","published_with_warning","published"]},"publicNote":{"anyOf":[{"type":"string"},{"type":"null"}]},"leadOrg":{"anyOf":[{"$ref":"#/components/schemas/Ref"},{"type":"null"}]},"reportCount":{"type":"integer"},"channels":{"type":"array","items":{"type":"string","enum":["app","web","whatsapp","sms","ussd","voice","responder","partner_api"]},"description":"Distinct channels the reports came through."},"responses":{"type":"array","items":{"$ref":"#/components/schemas/ResponseFull"},"description":"Full responses (replaces the summary list of the list endpoint)."},"reports":{"type":"object","properties":{"firstAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"lastAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"helpRequests":{"type":"integer"},"withGps":{"type":"integer"}},"required":["firstAt","lastAt","helpRequests","withGps"],"description":"Aggregates only."},"evidence":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["official","media","partner","sensor","photo","other"]},"status":{"type":"string","description":"`suggested` evidence does not count until a reviewer accepts it.","enum":["suggested","accepted","rejected"]},"supports":{"type":"boolean","description":"false = contradicts the incident."},"title":{"type":"string"},"source":{"anyOf":[{"type":"string"},{"type":"null"}]},"url":{"anyOf":[{"type":"string","format":"uri"},{"type":"null"}]},"at":{"type":"string","format":"date-time"},"org":{"anyOf":[{"type":"string","description":"Organisation that added it."},{"type":"null"}]}},"required":["id","kind","status","supports","title","source","url","at","org"]}},"discussion":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"author":{"type":"object","properties":{"name":{"type":"string"},"organisation":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","description":"Role label, e.g. \"Sub-county disaster officer\"."}},"required":["name","organisation","role"]},"body":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":["id","author","body","at"]}}},"required":["id","title","ward","subCounty","category","categoryLabel","severity","status","lat","lng","createdAt","updatedAt","resolvedAt","credibility","publicStatus","publicNote","leadOrg","reportCount","channels","responses","reports","evidence","discussion"]},"ResponseFull":{"type":"object","properties":{"id":{"type":"string"},"org":{"$ref":"#/components/schemas/Ref"},"status":{"type":"string","enum":["offered","lead","supporting","on_site","completed","withdrawn","declined"]},"statusLabel":{"type":"string"},"proposedLead":{"type":"boolean"},"interventions":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/InterventionId"},"label":{"type":"string"}},"required":["id","label"]}},"description":{"type":"string"},"resources":{"type":"string"},"etaMinutes":{"anyOf":[{"type":"integer"},{"type":"null"}]},"overlaps":{"type":"array","items":{"$ref":"#/components/schemas/InterventionId"},"description":"Interventions another engaged organisation (lead, supporting, on site) also committed to — a duplication warning."},"outsideOrgArea":{"type":"boolean","description":"The organisation has not registered this ward as an operating area."},"decisionNote":{"anyOf":[{"type":"string","description":"Note from the county when coordinating."},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","org","status","statusLabel","proposedLead","interventions","description","resources","etaMinutes","overlaps","outsideOrgArea","decisionNote","createdAt","updatedAt"]},"Response":{"type":"object","properties":{"id":{"type":"string"},"incidentId":{"type":"string"},"org":{"$ref":"#/components/schemas/Ref"},"status":{"type":"string","enum":["offered","lead","supporting","on_site","completed","withdrawn","declined"]},"statusLabel":{"type":"string"},"proposedLead":{"type":"boolean"},"interventions":{"type":"array","items":{"$ref":"#/components/schemas/InterventionId"}},"description":{"type":"string"},"resources":{"type":"string"},"etaMinutes":{"anyOf":[{"type":"integer"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","incidentId","org","status","statusLabel","proposedLead","interventions","description","resources","etaMinutes","createdAt","updatedAt"]},"OfferInput":{"type":"object","properties":{"interventions":{"type":"array","items":{"$ref":"#/components/schemas/InterventionId"},"minItems":1},"description":{"type":"string","maxLength":600,"default":""},"resources":{"type":"string","description":"What you bring (vehicles, kits, staff).","maxLength":300,"default":""},"etaMinutes":{"type":"integer","minimum":0,"maximum":10080,"description":"Minutes until you can be on site."},"proposeLead":{"type":"boolean","default":false,"description":"Offer to act as lead agency."}},"required":["interventions"]},"ResponseStatusInput":{"type":"object","properties":{"status":{"type":"string","enum":["on_site","completed","withdrawn"]},"note":{"type":"string","maxLength":500}},"required":["status"]},"EvidenceInput":{"type":"object","properties":{"kind":{"type":"string","description":"`partner`: your own staff confirm (counts at once). `media`: news coverage. `other`: anything else (both wait for review).","enum":["partner","media","other"]},"title":{"type":"string","minLength":3,"maxLength":200},"url":{"type":"string","description":"Full https:// link, or empty.","format":"uri"},"source":{"type":"string","description":"Defaults to the link’s host name.","maxLength":120},"note":{"type":"string","maxLength":1000},"supports":{"type":"boolean","default":true,"description":"false to contradict the incident."}},"required":["kind","title"]},"ReportInput":{"type":"object","properties":{"kind":{"type":"string","description":"`help` = someone needs help (at least severe priority).","enum":["hazard","help"],"default":"hazard"},"text":{"type":"string","minLength":3,"maxLength":2000},"lang":{"type":"string","enum":["en","sw","so"],"default":"en"},"wardId":{"type":"string","description":"Required unless lat and lng are given."},"lat":{"type":"number","minimum":-90,"maximum":90},"lng":{"type":"number","minimum":-180,"maximum":180},"placeName":{"type":"string","maxLength":160},"category":{"type":"string","description":"Filled in by triage when omitted.","enum":["road_cut","house_flooded","people_stranded","livestock","water_sanitation","health","infrastructure","rumour","other"]},"reporterPhone":{"type":"string","description":"Optional. Used only to recognise the same person across channels (de-duplication and track record). Never returned.","maxLength":40},"externalId":{"type":"string","description":"Your own record id, echoed back.","maxLength":120}},"required":["text"]},"ReportResult":{"type":"object","properties":{"ref":{"type":"string","description":"Human reference, e.g. MDR-4532."},"reportId":{"type":"string"},"incidentId":{"type":"string"},"grouped":{"type":"boolean","description":"true if it joined an existing incident."},"ward":{"$ref":"#/components/schemas/Ref"},"category":{"anyOf":[{"type":"string"},{"type":"null"}]},"severity":{"anyOf":[{"type":"string"},{"type":"null"}]},"credibility":{"anyOf":[{"$ref":"#/components/schemas/Credibility"},{"type":"null"}]},"externalId":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["ref","reportId","incidentId","grouped","ward","category","severity","credibility","externalId"]},"Trilingual":{"type":"object","properties":{"en":{"type":"string"},"sw":{"type":"string"},"so":{"type":"string"}},"required":["en","sw","so"]},"Alert":{"type":"object","properties":{"id":{"type":"string"},"hazard":{"type":"string","enum":["flood","flash_flood","disease","landslide","storm","other"]},"level":{"type":"integer","enum":[1,2,3,4]},"levelLabel":{"type":"string","enum":["Advisory","Watch","Warning","Emergency"]},"wards":{"type":"array","items":{"$ref":"#/components/schemas/Ref"}},"title":{"$ref":"#/components/schemas/Trilingual"},"body":{"$ref":"#/components/schemas/Trilingual"},"actions":{"type":"object","properties":{"en":{"type":"array","items":{"type":"string"}},"sw":{"type":"array","items":{"type":"string"}},"so":{"type":"array","items":{"type":"string"}}},"required":["en","sw","so"]},"issuer":{"type":"string"},"effective":{"type":"string","format":"date-time"},"expires":{"type":"string","format":"date-time"},"sentAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"channels":{"type":"array","items":{"type":"string","enum":["cell_broadcast","sms","push","whatsapp","radio"]}},"capUrl":{"type":"string","description":"CAP 1.2 document for this alert."}},"required":["id","hazard","level","levelLabel","wards","title","body","actions","issuer","effective","expires","sentAt","channels","capUrl"]},"Organisation":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["government","red_cross","un","ngo","private"]},"description":{"type":"string"},"services":{"type":"array","items":{"type":"object","properties":{"id":{"$ref":"#/components/schemas/InterventionId"},"label":{"type":"string"}},"required":["id","label"]}},"contact":{"type":"object","properties":{"phone":{"anyOf":[{"type":"string","description":"Organisation desk line."},{"type":"null"}]},"email":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["phone","email"]},"operatingAreas":{"type":"array","items":{"$ref":"#/components/schemas/AreaRef"}},"wards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"fieldOfficers":{"type":"integer"}},"required":["id","name","fieldOfficers"]}},"fieldOfficersByWard":{"type":"object","additionalProperties":{"type":"integer"},"description":"Ward id → number of field officers (volunteers, chiefs) assigned."},"members":{"type":"object","properties":{"total":{"type":"integer"},"field":{"type":"integer"},"desk":{"type":"integer"}},"required":["total","field","desk"]},"activeResponses":{"type":"integer"}},"required":["id","name","kind","description","services","contact","operatingAreas","wards","fieldOfficersByWard","members","activeResponses"]},"WebhookEnvelope":{"type":"object","properties":{"id":{"type":"string","description":"Unique event id, e.g. evt_3f9a…; use it to ignore duplicates."},"event":{"type":"string","enum":["incident.created","incident.updated","incident.response","alert.sent"]},"created":{"type":"string","format":"date-time"},"data":{"type":"object","description":"Event-specific fields. Fetch GET /incidents/{id} for the full picture."}},"required":["id","event","created","data"]}}}}