From zero knowledge to live humanitarian data in about ten minutes — the mental model, your first authenticated request, and two real queries.
This is the front door. If you’ve never touched the CLEAR API before, read this page top to bottom. By the end you’ll understand how the data is shaped and you’ll have pulled real records with your own API key. Everything else in these docs — the Queries, Mutations, and Types reference — is there to look things up after you understand the shape of the system.
1. The mental model
CLEAR is a five-tier graph. Source observations flow in at the bottom and are progressively grouped, classified, and escalated into human-readable advisories. Almost every query you write touches one of these five tiers:
A single source observation ingested from a source (Dataminr, ACLED, GDACS) or filed manually by a field officer. Upstream payloads are stored internally and are not returned on this type.
A user-curated aggregation of related events, enriched by an LLM with a summary, forward scenarios, and a needs analysis.
Two things to internalise. First, the tiers build upward: a Signal links to the Event it belongs to, which links to any Alert raised from it. Second, everything is geolocated — signals, events, and alerts all reference the Location hierarchy. That’s why the “by location” queries are the most powerful way to slice the data.
One staging area sits in front of tier 2. The ground staging tier holds staged Signals — messages ingested from ground sources such as WhatsApp groups (GroundMessage) — grouped into threads (GroundThread). A thread is a cluster of staged Signals with a correction lifecycle; when a reviewer approves a thread for publication, it is promoted and becomes a Signal. Nothing enters the signals graph from a ground source without passing that review gate.
New to GraphQL? You send one POST request to /graphql with a query naming exactly the fields you want, and you get back exactly those fields — no over-fetching, no guessing at response shapes. The GraphQL Sandbox autocompletes every field as you type, which is the fastest way to explore.
2. Get set up
You need an account and an API key. Both live in the Developer Portal.
In the portal, open API Keys and create one. Copy it immediately — the full key is shown only once.
Treat your key like a password. Keep it in an environment variable or secrets manager — never in client-side code or version control.
3. Your first request
The me query is the simplest authenticated call: it returns the account your key belongs to. Run it first to confirm your key works before you touch real data. Replace YOUR_API_KEY with the key you just generated:
curl -X POST https://api.clearinitiative.io/graphql \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"{ me { id email role } }"}'
If me comes back null, your key isn’t being read — double-check the Authorization header and that the key hasn’t been revoked in the portal.
4. Pull real data
Now something useful. Locations are the backbone of the graph, so start there: this lists every country CLEAR tracks (hierarchy level 0), with each one’s id, name, and resident population.
curl -X POST https://api.clearinitiative.io/graphql \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"{ locations(level: 0) { id name population } }"}'
You’ll get back an array of Location objects. Grab the id of a country that interests you — you’ll feed it into the next query.
level walks the hierarchy: 0 = country, 1 = state/province, 2 = city, and so on. Pass a country’s id to location(id: …) and request children to drill down a level at a time.
5. Slice by location
This is where it gets powerful. eventsByLocation returns every event whose origin, destination, or general location falls within a location and all of its descendants — so one country id gives you everything happening anywhere inside that country. Drop in the id from the previous step:
curl -X POST https://api.clearinitiative.io/graphql \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"query($loc: String!) { eventsByLocation(locationId: $loc) { id title severity types generalLocation { name level } } }","variables":{"loc":"YOUR_LOCATION_ID"}}'
Each Event comes back with a severity from 1 (low) to 5 (severe), its disaster-type types tags, and the place it’s bound to. From any event you can follow the graph further — ask for its signals to see the source observations underneath (title, location, severity — not the upstream source payload), or its alerts to see what was escalated from it.
The plain events, signals, and alerts lists are scoped to a team. If you’re not an admin, pass a teamId for a team you belong to (find yours via the myTeams query). The …ByLocation queries shown here have no such requirement, which is why they’re the easiest place to start.
Where to go next
You now know the shape of the graph and how to authenticate, query, and slice by location. From here:
Browse the full Queries and Types reference below — it’s auto-generated from the live schema, so it’s always current.
Open the GraphQL Sandbox to build queries interactively with field autocomplete.
Read the Authentication section for the browser/cookie flow if you’re building a web app rather than a server integration.
Welcome to the CLEAR API - your gateway to humanitarian intelligence.
The CLEAR API gives you programmatic access to signals, events, alerts, data sources, and geographic location data through a single GraphQL endpoint. Whether you’re building a monitoring dashboard, integrating alerts into your workflow, or analysing humanitarian patterns, this API has you covered.
Everything here is accessible via GraphQL at /graphql. You send a query describing exactly the data you want, and you get back precisely that — nothing more, nothing less.
Read an Event’s figures in the CLEAR Domain Ontology’s shape — one of seven metrics, with method, attribution, bounds and both time axes. Corrections supersede; nothing is overwritten.
Request an Event enrichment (today a web search, whose Worker proposes signals — CaseProposals — for analysts to accept or reject; one Task per source kind) and, as a Worker with the worker role, claim, heartbeat, complete or fail Tasks over GraphQL alone.
Quick Start
Go from zero to your first API response in three steps.
1
Create an account
Head to the Developer Portal and sign up. It takes about ten seconds.
2
Generate an API key
In the portal, go to API Keys and create one. Copy it immediately — you won’t see it again.
3
Make your first query
Send a request with your key in the Authorization header:
curl -X POST https://api.clearinitiative.io/graphql \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"{ me { id email } }"}'
Want to explore interactively? Open the GraphQL Sandbox to browse the full schema, autocomplete queries, and test requests in your browser.
Authentication
Two ways to authenticate, depending on your use case.
API Keys (server-to-server)
Pass your key as a Bearer token in the Authorization header:
Authorization: Bearer sk_live_your_key_here
Never expose API keys in client-side code or version control. Store them in environment variables or a secrets manager.
Session Cookies (browser apps)
Sign in via the REST auth API. The session cookie is set automatically and sent with subsequent requests:
// Sign in
const res = await fetch('/api/auth/sign-in/email', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ email: 'you@example.com', password: '...' }),
});
// Then query (cookie sent automatically)
const data = await fetch('/graphql', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
credentials: 'include',
body: JSON.stringify({ query: '{ me { id email } }' }),
});
Queries
Name
Returns
Description
me
User
Returns the currently authenticated user, or null if not signed in.
users
[User!]!
List all users.
user
User
Look up a user by ID.
id: String!
alerts
[Alert!]!
List alerts. Requires authentication. Admins may omit teamId to list all; non-admins must provide a teamId for a team they belong to.
Look up an alert by ID. Requires authentication. Non-admins can only access alerts within their team scope.
id: String!
signals
[Signal!]!
List signals. Requires authentication. includeDummy defaults to false.
teamId: StringincludeDummy: Boolean
signal
Signal
Look up a signal by ID. Requires authentication. Non-admins can only access signals within their team scope.
id: String!
signalsByLocation
[Signal!]!
List signals by location. Returns all signals whose origin, destination, or general location is within the given location (including descendants).
locationId: String!
signalLocationChallenges
[SignalLocationChallenge!]!
Open Signal Location challenges (for map dual-pin rendering). Team-scoped
like signals when teamId is given; status defaults to "consideration".
teamId: Stringstatus: String
pendingSignals
[Signal!]!
Signals awaiting downstream processing (status = NEW), oldest-first — the
Dagster event-driven drain. `source` filters by DataSource name (e.g.
"dataminr"); `first` caps the batch (default 100, max 500). Admin/pipeline only.
first: Intsource: String
events
[Event!]!
List events. Requires authentication. includeDummy defaults to false.
teamId: StringincludeDummy: Boolean
event
Event
Look up an event by ID. Requires authentication. Non-admins can only access events within their team scope.
id: String!
publicEvent
PublicEvent
Resolve a public share-link to its cached event snapshot. No auth -
the (eventId, token) pair from the URL is the gate, and the snapshot
only contains the safe fields enumerated on `PublicEvent`. Returns
null when the Redis cache has no entry for that pair (link expired,
revoked, or evicted under memory pressure - caller treats all three
the same).
eventId: String!token: String!
existingPublicEventLink
CreatePublicEventLinkResult
Look up the most recently-minted public share link for an event,
if one still exists in the cache. The Share modal calls this on
open so it can reuse an existing link rather than minting a fresh
token every time. Returns null when no live link exists - the
caller then mints one via `createPublicEventLink`. Requires
`requireContentReader` (admin / analyst / viewer); pending users
are blocked.
eventId: String!
eventsPendingAlert
[Event!]!
Events awaiting an alert (severity >= minSeverity AND no alert row yet AND
a signal within the last `maxAgeHours`), oldest-first by the event's
earliest-signal timestamp — the Dagster alert-stage queue. `first` caps the
batch (default 100, max 500); `minSeverity` floors the severity (default 4);
`maxAgeHours` bounds staleness on the latest signal's real-world time so the
historical backlog / backdated backfill never alerts (default 48; 0 disables).
Admin/pipeline only.
first: IntminSeverity: IntmaxAgeHours: Int
eventsByLocation
[Event!]!
List events by location. Returns all events whose origin, destination, or general location is within the given location (including descendants).
locationId: String!
alertsByLocation
[Alert!]!
List alerts by location. Returns all alerts whose event's location is within the given location (including descendants).
locationId: String!status: AlertStatus
dataSources
[DataSource!]!
List all data sources.
dataSource
DataSource
Look up a data source by ID.
id: String!
locations
[Location!]!
List locations, optionally filtered by hierarchy level (0 = country, 1 = state, etc.).
level: Int
location
Location
Look up a location by ID.
id: String!
notifications
[Notification!]!
List notifications, optionally filtered by status.
status: NotificationStatus
notification
Notification
Look up a notification by ID.
id: String!
featureFlags
[FeatureFlag!]!
List all feature flags.
featureFlag
FeatureFlag
Look up a feature flag by its unique key.
key: String!
disasterTypes
[DisasterType!]!
List all disaster type classifications (flat list of level-3 rows).
disasterType
DisasterType
Look up a disaster type by ID.
id: String!
disasterTypeHierarchy
[DisasterLevel1!]!
List disaster types grouped into the 3-level hierarchy (level1 > level2 > level3).
locationMetadata
[LocationMetadata!]!
List metadata entries for a location, optionally filtered by type.
By default only the CURRENT value is returned (validTo is null). Pass
current: false to include the full history.
locationId: String!type: Stringcurrent: Boolean
allLocationMetadata
[LocationMetadata!]!
List every locationMetadata entry of a given type across all locations.
By default only current values. Pass current: false for the full history.
type: String!current: Boolean
locationMetadataHistory
[LocationMetadata!]!
History of a (location, type) pair - newest first. Includes the current
row plus every superseded one.
locationId: String!type: String!
myApiKeys
[ApiKey!]!
List all API keys belonging to the authenticated user. Requires authentication.
conversation
Conversation
A CLEAR Agent Conversation by id: your own, or anyone's for a platform
admin (read-only, and logged as `conversation.admin_read`). Null if no
Conversation has that id; FORBIDDEN if it belongs to another user.
Approved users only.
id: String!
myConversations
[Conversation!]!
Your CLEAR Agent Conversations, most recently active first. Approved
users only.
first: Int — Max rows to return (1–100, default 20).after: String — The `cursor` of the last Conversation on the previous page. Omit
for the first page.
conversationMessagesByIds
[ConversationMessage!]!
Messages from your own Conversations by id (at most 200), oldest
first. Ids you don't own are left out. The CLEAR Agent's memory uses this
to resolve messages it knows only by id. Approved users only.
ids: [String!]!
myAgentBudget
AgentBudget!
Your daily CLEAR Agent budget: the limit, what you've spent since UTC
midnight, and when it resets. Approved users only.
myAgentWorkingMemory
AgentWorkingMemory
Your CLEAR Agent working memory, or null if the Agent hasn't saved any.
Approved users only.
userConversations
[Conversation!]!
Admin audit: one user's Conversations, most recently active first.
Read-only; each call is logged as `conversation.admin_read`. Admin only.
userId: String!first: Int — Max rows to return (1–100, default 20).after: String — The `cursor` of the last Conversation on the previous page.
myOrganisations
[Organisation!]!
List organisations the authenticated user belongs to.
organisation
Organisation
Look up an organisation by ID. Requires membership or global admin.
id: String!
myTeams
[Team!]!
List teams the authenticated user belongs to.
team
Team
Look up a team by ID. Requires membership or global admin.
id: String!
pendingInvites
[Invitation!]!
List pending invitations for an organisation. Requires org admin.
organisationId: String!
invitationByToken
InvitationInfo
Look up an invitation by token (public - used on accept-invite page).
token: String!
myAlertSubscriptions
[AlertSubscription!]!
List the authenticated user's alert subscriptions.
alertSubscriptionsByLocation
[AlertSubscription!]!
List all alert subscriptions for a location (admin only).
locationId: String!
crises
[Crisis!]!
List all crises.
crisis
Crisis
Look up a crisis by ID.
id: String!
pendingCrises
[Crisis!]!
Crises awaiting enrichment (enrichmentStatus = PENDING), oldest-first — the
Dagster enrichment drain. `first` caps the batch (default 100, max 500).
Admin/pipeline only.
first: Int
alertsPage
AlertsPage!
Paginated alerts feed with severity / location / type / date filters and
explicit ordering. Use this instead of `alerts(...)` when the UI needs
pages or a totalCount.
input: AlertsPageInput
eventsPage
EventsPage!
Paginated events feed (same filter shape as alertsPage, plus event-only
options). Honours teamId as a location-scope filter.
input: EventsPageInput
signalsPage
SignalsPage!
Paginated signals feed with source-based filtering.
input: SignalsPageInput
entityStats
EntityStats!
Cross-entity stats query - returns a total plus optional buckets grouped
by type / severity / day / week / month. Filter shape mirrors the page
queries so a "current view" can compute its own counts.
input: EntityStatsInput!
nominatimCacheEntry
NominatimCacheEntry
Look up a cached Nominatim geocoder response by query hash. Returns
null when the entry is missing or expired (admin/pipeline only).
queryHash: String!
activityLogs
[ActivityLog!]!
Paginated activity log. Admin only. Newest first.
filter: ActivityLogFilterInputlimit: Intoffset: Int
activityStats
ActivityStats!
Aggregated activity counts + per-user + per-day breakdown for the
admin dashboard. Admin only. Default window: last 30 days.
from: DateTimeto: DateTime
userEngagement
UserEngagementMetrics!
Point-in-time user-engagement summary: DAU, WAU, MAU, and the
DAU/MAU stickiness ratio. Derived from auth.login activity. Admin
only. `asOf` defaults to NOW(); pass a historical timestamp to
compute as-of that date.
asOf: DateTime
dauSeries
[DauPoint!]!
Daily Active Users time series - one point per UTC date in the
window. Admin only. Days with zero logins are omitted; the dashboard
can backfill them client-side when plotting.
from: DateTime!to: DateTime!
mauSeries
[MauPoint!]!
Monthly Active Users time series - one point per UTC calendar
month in the window. Admin only.
from: DateTime!to: DateTime!
pipelineCountries
[PipelineCountry!]!
The countries the CLEAR pipeline publishes a Situation Analysis for, with
each Country's bounding box. The scheduled publisher reads this to know which
countries to run. Requires authentication.
translations
[TranslationRow!]!
Translation rows currently stored for an entity, one per locale.
Admin/pipeline only. Used by clear-pipeline to compare stored source
hashes against the canonical row and decide which fields to re-translate.
entityType: String!entityId: String!
pendingTranslations
[TranslationQueueItem!]!
Entities enqueued for (re)translation, oldest-first — the Dagster
translation drain (durable replacement for the lazy-on-read Celery enqueue).
Optional entityType/locale filters; `first` caps the batch (default 100, max
500). Admin/pipeline only.
first: IntentityType: Stringlocale: String
translationCoverage
[TranslationCoverage!]!
Per-(entityType, locale) translation coverage snapshot for the
admin dashboard. Admin only. Each row reports canonicalCount (how
many entities of that type exist) and translatedCount (how many
have a translation row for that locale). Coverage = translated /
canonical.
entitiesMissingTranslation
[ID!]!
IDs of entities of the given type that have NO translation row
for the given locale. Admin/pipeline only. Lets the backfill
driver enqueue only entities the worker would actually translate,
instead of relying on per-task staleness diffs to no-op thousands
of already-current rounds. Stale rows (row exists but hashes are
out of date) are NOT returned here - they're rare and handled by
the per-entity enrichment hooks.
entityType: String!locale: String!
resolveKnowledgebaseLocation
String
Resolve a knowledge-base location reference to a `locations.id`.
Pcode wins over name; `adminLevel` narrows the name match so a
village that shares its state's name doesn't collide. Returns null
when neither the pcode nor the name matches - the ingest keeps the
raw pcode on the row so a future backfill can re-resolve. A name given
without `adminLevel` that matches more than one admin level is
ambiguous and also returns null (rather than guessing the deepest
match), so an unlevelled name never silently lands on the wrong tier.
Admin / pipeline only.
pcode: Stringname: StringadminLevel: Int
resolveGazetteerLocation
GazetteerHit
Resolve a place name against the offline GeoNames gazetteer - the
first tier of the hybrid geo-resolver. Tries an exact normalised-name
match, then a `pg_trgm` fuzzy match, preferring populated places / admin
areas (feature class P/A) and the more-populous tie-break. `countryCode`
(ISO-3166-1 alpha-2, e.g. "SD") scopes the search; omit to search every
loaded country. `minSimilarity` (default 0.4) floors the fuzzy match.
Returns null on no match - the geoparser then falls back to LocationIQ
for landmarks/POIs the gazetteer lacks. Admin / pipeline only.
Hybrid dense + BM25 retrieval over the knowledge base, fused
with Reciprocal Rank Fusion (k=60) and returned in descending
score order. Both retrievers run in parallel over the same filter
set; each contributes up to 50 candidates before fusion. The
embedding provider is the one configured in the environment -
keep the write and read sides on the same provider or turn on
`filters.currentEmbeddingModelOnly` to guarantee vector-space
consistency. Requires any authenticated content reader.
Two tiers are searched (ADR-0006): the ReliefWeb report KB (state /
analysis) and the incident index (event cards, always fresh). Each
tier is retrieved + RRF-fused independently, then merged tier-aware
so the few short incident cards are never buried by the many dense
report chunks. `mode` picks the merge: FRAME (a location+time frame
with little topical text — the situation-analysis case) returns a
report band + a quota-bounded incident band ordered by recency +
severity; TOPICAL (a strong free-text query — the chatbot case)
interleaves by relevance, gating weak incidents. AUTO picks FRAME
when the query is effectively empty/frame-only, else TOPICAL. Every
hit carries its `tier`.
query: String!filters: KnowledgebaseFilterslimit: Inttiers: [KnowledgebaseTier!] — Which tiers to search. Default: both (the KB is always fresh). Pass
[report] to get the pre-ADR-0006 report-only behaviour.mode: KnowledgebaseSearchMode
knowledgebaseIngestJob
KnowledgebaseIngestJob
Poll a Dagster run kicked off by `uploadKnowledgebaseDocument`.
Returns null when the runId doesn't exist on this Dagster instance
(e.g. Dagster was restarted with a fresh instance store, or the
runId was recorded against a different DAGSTER_URL). Requires any
authenticated content reader.
runId: String!
reportDatapoint
ReportDatapoint
One report's extracted structured datapoints. Returns null when
no extraction has been persisted yet (report ingested via vector
RAG but the datapoint pipeline hasn't caught up). Requires any
authenticated content reader.
reportId: String!
situationAnalysis
SituationAnalysis
Current situation-analysis snapshot for one bucket of a country.
Buckets are keyed `(countryLocationId, windowKind, windowStart)`.
By default reads the yearly bucket, where `year` derives
`windowStart = Jan 1` server-side and falls back to `year(now())`
when null - the dashboard's usual call. Pass `windowKind` +
`windowStart` instead to read a finer bucket (e.g. monthly, to diff
one month against the previous). Returns null when no snapshot
exists - the dashboard should render an empty state and wait for the
next weekly generation. Requires any authenticated content reader.
countryLocationId: String!year: IntwindowKind: String — Bucket granularity, part of the bucket key. Defaults to
`yearly`. The pipeline owns this taxonomy (currently `yearly`
and `monthly`), so it is not validated against a fixed list here -
an unknown value simply matches no row and returns null.windowStart: DateTime — Exact bucket start, matched for equality. Required when
`windowKind` is anything other than `yearly`, because a year
alone cannot identify a finer bucket. Must be the same instant the
writer used (midnight UTC on the first day of the window), so pass
the value the pipeline computed rather than reconstructing it.
`windowEnd` is never matched on.asOf: DateTime — Historical read - return the version that was current at
this timestamp (defaults to now).schemaVersion: String — Pin the read to a payload schema version. Defaults to the most
recently written version for the bucket. Versions coexist rather
than supersede - an older payload shape stays readable, so pass
this to keep a client on a shape it understands. Read
`schemaVersion` off the returned row to see what you got.
situationAnalysesForCountry
[SituationAnalysis!]!
Trend / history view - one row per year for a country, current
versions only, newest year first. Never mixes schema versions: a
bump changes what the numbers mean, so one series is always one
version. Requires any authenticated content reader.
countryLocationId: String!limit: IntschemaVersion: String — Pin the trend to a payload schema version. Defaults to the
country's most recently written version. Pass an older one to
chart a historical payload shape.
situationAnalysisById
SituationAnalysis
Read one situation-analysis snapshot by its row id, including
superseded history rows (the bucket-keyed `situationAnalysis` query
only returns the current row). Used by the translation pipeline to
fetch a specific generation's canonical prose. `data` is overlaid
with the caller's locale translation like every other read — the
pipeline calls it as `en` and gets canonical text back. Requires any
authenticated content reader.
id: String!
analysis
Analysis
Unified frame-scoped analysis (ADR-0007). Reads the current row for a
FRAME (locationIds / eventTypes / needSectors / window) — the generalised
successor to `situationAnalysis`, and the read path for "crisis
overview" frames. `windowEnd` null in the frame reads the rolling
("to present") row. Pass `asOf` for a historical read and
`schemaVersion` to pin a payload shape. Returns null when no analysis
exists for the frame yet. Requires any authenticated content reader.
Read one analysis by row id, including superseded history rows (the
frame-keyed `analysis` query only returns the current row). Requires any
authenticated content reader.
id: String!
analysisAutomations
[AnalysisAutomation!]!
List analysis automation subscriptions (ADR-0007 §5). Optionally scope
to a team or to enabled rows only. Requires any authenticated content
reader.
teamId: StringenabledOnly: Boolean
pendingAnalyses
[AnalysisRequest!]!
Pipeline drain (ADR-0007 §4): the oldest PENDING on-demand analysis
requests, so the generation sensor can pick them up. Admin / pipeline only.
limit: Int
dueAnalysisAutomations
[AnalysisAutomation!]!
Scheduler drain (ADR-0007 §5): enabled analysis automations that are DUE
(never run, or their nextRunAt has passed). The pipeline groups them by
frame and regenerates each at the minimum cadence across subscribers.
Admin / pipeline only.
limit: Int
frameEvidenceWatermark
FrameEvidenceWatermark!
Latest-evidence watermark for a frame (ADR-0008) over the `knowledgebase`
retrieval corpus — `latestEvidenceAt` (max ingestion time) + `evidenceCount`.
The pipeline drains compare it to the live analysis's `generatedAt` to decide
whether new evidence warrants a regeneration. Admin / pipeline only.
frame: AnalysisFrameInput!
reportFigures
[ReportFigure!]!
Captured infographics (charts/maps/tables/composite panels) filtered by the
SAME params as text — location / event type / need sector / time / kind — so a
figure can be attached to an answer scoped to a place + topic + period. Powers
figure attachment + on-demand infographic generation. Array filters match ANY
tag; time overlaps the window. Any authenticated content reader.
reportId: StringlocationIds: [String!]eventTypes: [String!]needSectors: [String!]kinds: [String!]timeRangeStart: DateTimetimeRangeEnd: DateTimefirst: Int — Max rows to return (1–200, default 50).after: String — Cursor for pagination: the `id` of the last figure from the previous
page. Rows after it (in the stable extractedAt/pageNumber/id order) are
returned. Omit for the first page; a report's figures are capped well
under 200 so most callers never need this.
hasAggregatedDatapoints
Boolean!
True when at least one current `aggregated_datapoints` row
exists for the given schema version. Used by the Dagster
aggregation asset to distinguish first-run backfill (wide
lookback window) from routine weekly refreshes (narrow window).
Pass `countryLocationId` (an admin-0 location id) to scope the
check to ONE country, so a newly-onboarded country's first run
uses the initial window even after other countries are established
— the four-tier walk always produces yearly/all-time buckets AT the
country location, so an A0 row is the per-country signal. Any
authenticated content reader - a cheap existence check.
schemaVersion: String!countryLocationId: String
aggregatedDatapoint
AggregatedDatapoint
Aggregated datapoints for a (window × window_kind × location)
scope. Cache-first: returns the pre-computed snapshot when one
is current (`validTo IS NULL` or covers the `asOf` timestamp);
otherwise assembles the bucket on-demand from `report_datapoints`
and returns it with `onDemand = true`. Returns null when no
contributing reports exist in scope.
locationId: String — Null = country-wide roll-up (yearly / all-time tiers).windowStart: DateTime!windowEnd: DateTime!windowKind: String!schemaVersion: String — Defaults to the currently-configured pipeline schema version.asOf: DateTime — Historical snapshot lookup - return the version that was current
at this timestamp. Defaults to `now`.
webhookSubscriptions
[WebhookSubscription!]!
All webhook subscriptions, newest first.
webhookSubscription
WebhookSubscription
One subscription by ID, or null if not found.
id: String!
webhookDeliveries
[WebhookDelivery!]!
Recent delivery attempts for a subscription, newest first.
subscriptionId: String!limit: Int
groundSources
[GroundSource!]!
All ground sources (per-source policy records), newest first.
groundThreads
[GroundThread!]!
Review queue: ground threads, newest first. Filter by source and/or
review state ("unverified" | "approved_private" | "approved_public" |
"rejected").
groundSourceId: StringreviewState: Stringlimit: Intoffset: Int
groundThread
GroundThread
One ground thread with its messages, or null if not found.
id: String!
groundMessages
[GroundMessage!]!
Staged messages, oldest first. Filter by source and/or thread.
groundSourceId: StringthreadId: Stringlimit: Intoffset: Int
groundMessagesForClassification
[GroundMessageForClassification!]!
PIPELINE CONTRACT (admin/pipeline only): a source's staged
messages, oldest first, projected for the classification/threading
worker — no private-tier sender identity. By default returns ALL
messages (classified and not) so one query powers both labelling and
thread assembly (clustering staged Signals into threads). Drains
pass `unclassifiedOnly` / `awaitingTranscript` to read only their
work queue — the default window is the oldest `limit` messages and
stops advancing once those are all done.
groundSourceId: String!limit: IntunclassifiedOnly: Boolean — Only messages with no classification yet — the enrichment
drain's queue. Excludes messages marked failed for enrichment, and
voice notes marked failed for transcription (they have no content to
enrich until a retry transcribes them).awaitingTranscript: Boolean — Only hotline voice notes with no transcript yet — the
transcription drain's queue. Excludes messages marked failed for
transcription.
groundThreadsForSource
[GroundThread]
PIPELINE CONTRACT (admin/pipeline only): threading context for the
classification worker — a source's existing threads, oldest first,
so late corrections/retractions can target an existing thread via
GroundThreadUpsertInput.threadId. `states` filters on
lifecycleState ("reported" | "updated" | "confirmed" | "corrected" |
"retracted"); omitted/empty returns all. The worker selects
{id, title, lifecycleState, reviewState, messageIds} — no message
content, no sender identity.
groundSourceId: String!states: [String!]
pipelineGroundSourceIds
[String!]!
PIPELINE CONTRACT (admin/pipeline only): active source ids for a
given kind, minimal projection (no consent/policy fields) — used by
the hotline enrichment job to enumerate sources to drain.
kind: StringisActive: Boolean
groundMessageForTranslation
GroundMessageForTranslation
PIPELINE CONTRACT (admin/pipeline only): the translate drain's
canonical fetch for a queued groundMessage translation — text and
detected language, no sender identity. Null if the message is gone.
id: String!
task
Task
One Task by id, or null. Any authenticated content reader; the
Task's status follows its Event's visibility. `lastError` is visible
to the requester and platform admins only.
id: String!
eventTasks
[Task!]!
Enrichment Tasks about an Event, newest first. Same gate as
`task`.
eventId: String!
myTasks
[Task!]!
The caller's own requests: Tasks they asked for, across every Event,
newest first — "what happened to the thing I asked for". Always scoped
to the signed-in requester; `status` narrows it. `lastError` is
present (the caller is the requester). Any approved content reader
except the worker role, which requests nothing.
status: TaskStatuslimit: Intoffset: Int
eventImpactPriors
[ImpactPrior!]!
History: the whole ImpactPriors Workers proposed for an Event in
V1–V3, newest first. Nothing creates them any more (the ImpactPrior is
computed, see `Event.computedImpactPriors`) and none can be decided.
An `accepted` one follows the Event's visibility; a `proposed` one
is visible to its requester and to deciders (admins and analysts); a
`rejected` one to deciders only.
eventId: String!
caseProposals
[CaseProposal!]!
The Inbox's per-case Review items (V4): CaseProposals in one state
across every Event, newest first — `proposed` by default. Platform
admins and analysts only, so the list is exactly what the caller may
decide.
state: CaseProposalStatelimit: Intoffset: Int
eventCaseProposals
[CaseProposal!]!
Web cases proposed for an Event, newest first. Same visibility as
`Event.caseProposals`.
eventId: String!
rejectedCaseUrls
[String!]!
Source URLs already rejected for an Event: a web Worker reads this
before searching and never proposes one again. The worker role,
platform admins and analysts.
eventId: String!
Mutations
Name
Returns
Description
createApiKey
CreateApiKeyPayload!
Create a new API key for the authenticated user.
input: CreateApiKeyInput!
revokeApiKey
ApiKey!
Revoke an API key by ID. Only the key owner or an admin can revoke.
id: String!
upsertConversation
Conversation!
Create one of your Conversations with the CLEAR Agent's thread id, or
update its title or metadata. FORBIDDEN if the id belongs to another user.
CLEAR Agent only (the owner's session plus the agent key).
input: UpsertConversationInput!
upsertConversationMessages
[ConversationMessage!]!
Create or replace messages in one of your Conversations, matched by id
(at most 200 per call). Only the owner's Conversations, admins included,
and CLEAR Agent only (the owner's session plus the agent key). An Answer
whose usage is recorded can't change. Returns the messages in input order.
Create or update your CLEAR Agent working memory. CLEAR Agent only (your
session plus the agent key).
input: SaveAgentWorkingMemoryInput!
recordConversationTurnUsage
ConversationMessage!
Record what a CLEAR Agent turn used (model, tokens, cost, latency) on
its Answer, an `assistant` message in one of your Conversations. The
cost counts toward your daily Agent budget. Write-once: FORBIDDEN if the
turn's usage is already recorded. Owner only, CLEAR Agent only (the
owner's session plus the agent key).
Mint a Redis-backed share token for an event. The snapshot of the
event's safe-to-share fields is stored under a key derived from
the eventId + token and lives for `ttlDays` days (default 30, max
90). Anyone who has the resulting URL can read the snapshot via
the `publicEvent(eventId, token)` query. Caller must be able to
read the event normally (admin / analyst / viewer); pending users
are blocked.
input: CreatePublicEventLinkInput!
revokePublicEventLink
Boolean!
Invalidate a public share token by deleting the cached snapshot.
Idempotent — revoking a missing key returns true. Caller must be
an approved user; ownership of the original link is not checked
because the link is by definition unauthenticated and the only
state to delete is the cache entry itself.
eventId: String!token: String!
createDevUser
CreateDevUserResult!
Provision a developer account from an approved waitlist application.
Creates the user, mints an initial API key (no expiry), issues a
long-lived set-password verification token, and sends the welcome
email. Requires global `admin`. The CRM write-back is the caller's
responsibility.
input: CreateDevUserInput!
rotateDevUserApiKey
RotateDevUserApiKeyResult!
Revoke every active API key for a dev user and issue a fresh one.
Notifies the user by email. Requires global `admin`.
userId: String!
approveUser
ApproveUserResult!
Approve a self-signed-up user. Flips their role from `pending`
to `viewer` (granting read access to signals / events / alerts /
crises) and moves their CRM contact from the prospects collection
into the approved collection — which fires Exponential's welcome
automation. The local role flip is authoritative; CRM updates are
best-effort and surface as fields on the result so the admin UI
can offer a retry. Requires global `admin`.
userId: String!
updateUserRole
User!
Set a user's global platform role (`viewer`, `analyst`, or
`admin`). Does not approve pending users — call `approveUser`
first. Requires global `admin`. Cannot demote yourself or the
last remaining admin. This is the product write path for the
Users-tab dropdown on the operator app; the Developer Portal
HTML form hits the same service via POST
`/portal/admin/users/role`.
userId: String!role: GlobalRole!
requestEmailVerification
Boolean!
Request an email verification link for the authenticated user.
verifyEmail
Boolean!
Verify email using a token from the verification link.
token: String!
updateProfile
User!
Update the authenticated user's profile and notification preferences.
input: UpdateProfileInput!
createAlert
Alert!
Create an alert from an event, notifying subscribers.
input: CreateAlertInput!
updateAlert
Alert!
Update an existing alert.
id: String!input: UpdateAlertInput!
deleteAlert
Boolean!
Delete an alert.
id: String!
archiveStaleAlerts
ArchiveStaleAlertsResult!
Archive published alerts whose event.lastSignalCreatedAt is older than
olderThanDays (default: 14). Sets alerts.status to 'archived'. Admin or
pipeline only. Returns the number of rows affected.
olderThanDays: Int
createSignal
Signal!
Create a signal from a data source.
input: CreateSignalInput!
markSignalsProcessed
Int!
Mark signals as done for the Dagster drain — the downstream pipeline calls
this after classify→group→alert. Sets status (PROCESSED by default, or FAILED)
and processedAt. Returns the number of rows updated. Idempotent. Admin/pipeline only.
ids: [String!]!status: SignalStatus
createManualSignal
Signal!
Create a manual signal from a field officer, partner, or government source.
Persists the signal and sends it to the pipeline for event grouping and auto-escalation.
input: CreateManualSignalInput!
updateSignalSeverity
Signal!
Update a signal's severity score.
id: String!severity: Int!
updateSignalGeoparsedData
Signal!
Attach the clear-pipeline geoparser's result to an existing signal.
Used for the manual-signal flow, where the signal is created via
createManualSignal before the pipeline has a chance to run the geoparser.
Stores the structured candidate verbatim; does not change locationId.
Admin/pipeline only.
id: String!geoparsedData: JSON!
updateSignalLocation
Signal!
Set (or replace) an existing signal's generalLocation. Used by the
manual-signal pipeline path: when the user didn't pick a location and
the geoparser resolved a landmark, we promote it to an L4 via
findOrCreateLandmarkL4 and then wire the signal to it so downstream
event grouping can key on the resolved admin-2 district instead of
creating an isolated event. Admin/pipeline only.
id: String!locationId: String!
updateSignalContent
Signal!
Apply an in-place content revision to an existing signal (e.g. IDMC's
IDU rows being revised upstream — same id, changed figures/role/dates/
location). Only writes when input.contentHash differs from the stored
contentHash; a no-op retry (e.g. the pipeline's Redis seen-set re-sending
unchanged data) leaves the row and lastRevisedAt untouched. Admin/pipeline
only.
input: UpdateSignalContentInput!
deleteSignal
Boolean!
Delete a signal.
id: String!
submitSignalLocationChallenge
SignalLocationChallenge!
Create or replace the open (consideration) Location challenge for a Signal.
Auth: any approved logged-in team member who can view the Signal. Queue only —
does NOT accept/reject and does NOT mutate the Signal's geometry.
input: SubmitSignalLocationChallengeInput!
createEvent
Event!
Create a new event from signals.
input: CreateEventInput!
updateEvent
Event!
Update an existing event.
id: String!input: UpdateEventInput!
deleteEvent
Boolean!
Delete an event.
id: String!
escalateEvent
EventEscalation!
Escalate an event: creates an alert (published) and records the user escalation.
If the event already has a published alert, just records the user escalation.
teamId (optional) admits a team_admin or field_coordinator on that team
even without a global admin/analyst role — purely an authorisation hint,
not stored on the event.
eventId: String!userId: String!teamId: String
createDataSource
DataSource!
Create a new data source.
input: CreateDataSourceInput!
updateDataSource
DataSource!
Update an existing data source.
id: String!input: UpdateDataSourceInput!
deleteDataSource
Boolean!
Delete a data source.
id: String!
resolveDataSource
String!
Idempotently resolve an organisation/source name to a data_sources id,
creating an ungraded row if none matches (admin/pipeline only). Matching order:
exact name/synonym → infoUrl (when homepage given) → pg_trgm fuzzy (>= minSimilarity,
default 0.6) → create. On a URL/fuzzy hit the incoming name is appended as a synonym so
future lookups hit exactly. Returns the resolved data_sources id. See clear-pipeline ADR-0004.
name: String!homepage: StringminSimilarity: Float
createLocation
Location!
Create a new location.
input: CreateLocationInput!
ensureCountryLocation
Location!
Idempotently resolve a level-0 Country location by exact name, creating it
with a bounding-box MULTIPOLYGON geometry if absent (admin/pipeline only).
bbox is [minLng, minLat, maxLng, maxLat]. Returns the (found or created)
Country — doubles as the pipeline's name→id resolution.
name: String!bbox: [Float!]!
updateLocation
Location!
Update an existing location.
id: String!input: UpdateLocationInput!
deleteLocation
Boolean!
Delete a location.
id: String!
updateLocationGeometry
Location!
Replace a location's geometry with the given GeoJSON (admin/pipeline only).
id: String!geometry: GeoJSON!
updateLocationPopulation
Location!
Set a location's cached population (admin/pipeline only).
id: String!population: String!
updateCrisisPopulation
Crisis!
Set a crisis's populationAffected + populationInArea (admin/pipeline only).
id: String!input: UpdateCrisisPopulationInput!
upsertLocationMetadata
LocationMetadata!
Create or update a location's metadata entry for a given type (admin/pipeline only).
Upsert keyed by (locationId, type).
input: UpsertLocationMetadataInput!
upsertLocationMetadataBatch
[LocationMetadata!]!
Bulk-upsert multiple (locationId, type, data) rows in a single call (admin/pipeline only).
Returns the current row for each input. Rows whose locationId doesn't exist are
skipped silently. Idempotent: an input whose blob is identical to the currently-open
row is left untouched (no new history version), so re-running an ingest with unchanged
data is a no-op.
inputs: [UpsertLocationMetadataInput!]!
deleteLocationMetadata
Boolean!
Delete a location's metadata entry for a given type (admin only).
locationId: String!type: String!
findOrCreateLandmarkL4
FindOrCreateLandmarkL4Result!
Find an existing level-4 location matching a geoparsed candidate, or
create one. Used by the clear-pipeline geoparser to promote a landmark
hit (e.g., "Nyala Airport") into a reusable A4 instead of letting the
resolver invent a fresh point-location for every signal. When sourceLat
and sourceLng are provided, the resolver verifies that the candidate's
containing A2 matches the source coord's containing A2 — on mismatch it
aborts with abortedReason="different_a2" so the caller can fall back to
source coords. Admin/pipeline only.
input: FindOrCreateLandmarkL4Input!
upsertNominatimCache
NominatimCacheEntry!
Upsert a Nominatim geocoder cache entry (admin/pipeline only).
Replaces any existing row with the same queryHash, resetting the TTL.
input: UpsertNominatimCacheInput!
setFeatureFlag
FeatureFlag!
Set the enabled state of a feature flag, identified by its string key.
Upserts the row so the same call works whether the key is already present.
Admin only — toggling features is an org-wide change, not a per-user
preference. Returns the persisted flag so callers can update local state
without an extra round-trip.
key: String!enabled: Boolean!
createNotification
Notification!
Create a notification for a user.
input: CreateNotificationInput!
createBulkNotifications
Int!
Create notifications for multiple users at once. Returns the count of notifications created.
input: CreateBulkNotificationsInput!
notifyAlertSubscribers
Int!
Notify all subscribers of a single alert (immediate frequency). Matches on event types and locations.
input: AlertNotifyInput!
notifyAlertDigest
Int!
Send a digest notification for multiple alerts to subscribers of the given frequency (daily/weekly/monthly).
input: AlertDigestInput!
deleteNotification
Boolean!
Delete a notification.
id: String!
markNotificationRead
Notification!
Mark a notification as read.
id: String!
markAllNotificationsRead
Boolean!
Mark all notifications as read for the authenticated user.
addFeedback
UserFeedback!
Add feedback (rating + optional text) to a signal or event.
input: AddFeedbackInput!
deleteFeedback
Boolean!
Delete your own feedback.
id: String!
addComment
UserComment!
Add a comment to a signal or event.
input: AddCommentInput!
replyToComment
UserComment!
Reply to an existing comment.
input: ReplyToCommentInput!
deleteComment
Boolean!
Delete your own comment.
id: String!
tagUsersInComment
UserComment!
Tag users in a comment.
commentId: String!userIds: [String!]!
createOrganisation
Organisation!
Create a new organisation. The creator becomes the first org_admin.
input: CreateOrganisationInput!
updateOrganisation
Organisation!
Update an existing organisation. Requires org_admin (or platform admin).
id: String!input: UpdateOrganisationInput!
addOrgMember
OrgMember!
Add a member to an organisation.
orgId: String!userId: String!role: OrgMemberRole
removeOrgMember
Boolean!
Remove a member from an organisation.
orgId: String!userId: String!
updateOrgMemberRole
OrgMember!
Change a member's role within an organisation. Requires the caller to be
a platform admin or an org_admin of the target organisation.
orgId: String!userId: String!role: OrgMemberRole!
deleteOrganisation
Boolean!
Delete an organisation and all its teams, members, and invitations. Requires global admin.
id: String!
createTeam
Team!
Create a new team within an organisation. Requires org_admin (or platform admin).
Set the locations a team is scoped to. Replaces all existing locations.
teamId: String!locationIds: [String!]!
setDefaultTeam
Team!
Set the authenticated user's default team (for frontend convenience).
teamId: String!
inviteUser
Invitation!
Invite a user to an organisation (and optionally a team). Sends invite email.
input: InviteUserInput!
acceptInvite
Boolean!
Accept an invitation. Creates user account if new, adds to org and team.
input: AcceptInviteInput!
cancelInvite
Boolean!
Cancel a pending invitation.
id: String!
resendInvite
Invitation!
Resend an invitation email (resets expiry to 7 days).
id: String!
requestPasswordReset
Boolean!
Request a password reset email (public, always returns true).
email: String!
resetPassword
Boolean!
Reset password using a token from the reset email.
token: String!newPassword: String!
subscribeToAlerts
AlertSubscription!
Subscribe to alerts for a specific type and location.
input: SubscribeToAlertsInput!
subscribeToAlertsBatch
[AlertSubscription!]!
Subscribe to alerts for multiple (location × alertType) combinations in a single call.
Returns the list of created subscriptions. Duplicates are skipped silently.
input: SubscribeToAlertsBatchInput!
updateAlertSubscription
AlertSubscription!
Update an existing alert subscription (channel, frequency, active).
id: String!input: UpdateAlertSubscriptionInput!
unsubscribeFromAlerts
Boolean!
Unsubscribe - deletes the subscription.
id: String!
createCrisisFromEvents
Crisis!
Create a new crisis from a list of event IDs. Links all provided events to the new crisis.
input: CreateCrisisFromEventsInput!
markCrisisEnriched
Crisis!
Mark a crisis ENRICHED for the Dagster drain — the enrichment consumer calls
this once narrative/scenarios/needs-analysis are current. Idempotent. Admin/pipeline only.
id: String!
addEventToCrisis
EventCrisis!
Add an existing event to an existing crisis. Idempotent - returns the existing link if one already exists.
crisisId: String!eventId: String!
removeEventFromCrisis
Crisis
Remove an event from a crisis. Recomputes populationAffected from the
remaining events and dispatches the enrichment task so title/summary get
regenerated to reflect the new event set. If the event being removed is
the LAST event, deletes the crisis entirely and returns null. Otherwise
returns the updated crisis (title/summary still show pre-removal values
until the async enrichment task completes).
crisisId: String!eventId: String!
updateCrisisTitle
Crisis!
Edit a crisis's title in place. Any approved user (admin, analyst or
viewer); a `pending` signup or the `worker` role is FORBIDDEN. Pass an
empty string to clear the field.
id: String!title: String!
updateCrisisDescription
Crisis!
Edit the human-facing description on a crisis. The crisis's summary
column stores JSON of the form description+tldr — this mutation updates
just the description key and preserves any existing tldr bullets (which
the LLM enrichment task generates). Any approved user (admin, analyst or
viewer); a `pending` signup or the `worker` role is FORBIDDEN. Pass an
empty string to clear the description without disturbing the tldr.
id: String!description: String!
deleteCrisis
Boolean!
Delete a crisis. Cascades the eventCrises join rows, user feedback,
and user comments via the FK constraints. Platform admins only.
id: String!
addCrisisAttachments
Crisis!
Append S3 keys to a crisis's attachments list. Idempotent — keys
already present in the list are skipped silently. Returns the updated
crisis with the new list. Any approved user (admin, analyst or
viewer); a `pending` signup or the `worker` role is FORBIDDEN.
id: String!keys: [String!]!
removeCrisisAttachment
Crisis!
Remove an S3 key from a crisis's attachments list. Does NOT delete
the underlying S3 object (operators can clean those up separately).
Returns the updated crisis. Any approved user (admin, analyst or
viewer); a `pending` signup or the `worker` role is FORBIDDEN.
id: String!key: String!
setCrisisNeedsAnalysis
Crisis!
Set the LLM-generated NRC SAF needs analysis inside the crisis's
needs JSONB. Merges generalSummary and sector keys into the existing
object so other keys on needs are preserved. Admin/pipeline only.
Upsert one or more per-locale translation rows for an event,
crisis, or location. The translated data blob mirrors the canonical
entity's JSON shape per locale. Admin/pipeline only. Clears any matching
rows from the translation queue (the write is the drain-completion signal).
input: UpsertTranslationsInput!
enqueueTranslation
TranslationQueueItem!
Enqueue an entity for (re)translation at a locale — the durable replacement
for the lazy-on-read Celery enqueue. Idempotent (one row per entity+locale).
Admin/pipeline only.
Remove an entity/locale from the translation queue (explicit drain
completion). Returns true when a queued row was removed. upsertTranslations
clears the queue itself, so this is only for consumers not writing via it.
Admin/pipeline only.
Replace all knowledgebase rows for `reportId` with `chunks`.
Runs inside one transaction — a failed insert rolls back the
delete so a re-run can retry cleanly. Vector length is validated
against the pgvector column dimension (1024) on the server;
mismatched rows are rejected before the write hits Postgres.
Admin/pipeline only.
Synthesise, embed, and upsert incident-tier "event cards" into
`events_index` for the given events (ADR-0006) — replace-on-revise,
keyed by event id. Call this when events are created or revised (from
the signal→event grouping step, or a periodic catch-up) to keep the
incident tier of `searchKnowledgebase` fresh. Embedding uses the same
provider+model as the report KB. Admin/pipeline only.
eventIds: [String!]!
upsertReportDatapoints
UpsertReportDatapointsResult!
Replace the `report_datapoints` row for `input.reportId`.
Admin / pipeline only. The dagster-quickstart datapoints
extraction asset is the primary caller; hand-invocation is
supported for backfills and re-extraction. Idempotent — the row
is uniquely keyed on `report_id`.
input: UpsertReportDatapointsInput!
upsertSituationAnalysis
UpsertSituationAnalysisResult!
Insert a fresh situation-analysis snapshot for
(`input.countryLocationId`, `input.windowStart`,
`input.windowEnd`) and stamp `validTo = now()` on the
previous current row for the same bucket in the same
transaction. History rows are preserved. Admin / pipeline only —
the Dagster `weekly_situation_analyses` asset is the primary
caller.
input: UpsertSituationAnalysisInput!
upsertAnalysis
UpsertAnalysisResult!
Upsert a unified frame-scoped analysis (ADR-0007). The pipeline
generator's write path: bitemporal supersede-then-insert keyed on the
frame columns (locationIds / eventTypes / needSectors / windowStart /
windowEnd), stamping `validTo` on the previous current row for the same
frame in the same transaction. History rows are preserved. Frame arrays are
canonicalised (sorted + de-duplicated) server-side. Admin / pipeline only.
input: UpsertAnalysisInput!
touchAnalysisSynced
Boolean!
Pipeline: bump the current analysis row's `lastSyncedAt` for a frame
WITHOUT regenerating (ADR-0008) — used when the drain's gate decides to skip
(within the 24h floor, or no new evidence). Returns false when no current row
exists for the frame. Admin / pipeline only.
frame: AnalysisFrameInput!
createAnalysisAutomation
AnalysisAutomation!
Create an analysis automation — a subscription that keeps a frame's
analysis current on a cadence (ADR-0007 §5). Admin / analyst.
input: CreateAnalysisAutomationInput!
updateAnalysisAutomation
AnalysisAutomation!
Update an analysis automation's cadence or enabled flag. Admin / analyst.
id: String!input: UpdateAnalysisAutomationInput!
deleteAnalysisAutomation
Boolean!
Delete an analysis automation subscription. Admin / analyst.
id: String!
requestAnalysis
AnalysisRequest!
Enqueue an on-demand analysis for a frame (ADR-0007 §4). Dedupes against
an existing PENDING request for the same frame. Admin / analyst.
input: RequestAnalysisInput!
markAnalysisRequestGenerated
AnalysisRequest!
Pipeline: mark a drained request GENERATED after its analysis was
upserted. Admin / pipeline only.
id: String!
markAnalysisRequestFailed
AnalysisRequest!
Pipeline: record a generation failure on a request (bumps the attempt
counter). Admin / pipeline only.
id: String!error: String
markAnalysisAutomationsRan
Int!
Scheduler: stamp lastRunAt + nextRunAt (from each row's cadence) on the
automations whose frame was just regenerated (ADR-0007 §5) — pass all the
ids sharing that frame. Returns the count updated. Admin / pipeline only.
ids: [String!]!
upsertReportFigures
UpsertReportFiguresResult!
Replace a report's captured infographics (image asset store). Pipeline-only;
delete-then-insert like `upsertReportDatapoints`.
input: UpsertReportFiguresInput!
refreshAggregatedDatapoints
RefreshAggregatedDatapointsResult!
Pre-compute all four aggregation tiers (weekly × A2, monthly × A1,
yearly × country, all-time × country) for reports whose
`reportingPeriodEnd` falls in `[from, to]`. Each computed
bucket is inserted with `validFrom = now()`; the previous
"current" row for the same bucket key has its `validTo` stamped
in the same transaction. History rows are preserved. Admin /
pipeline only.
Pass `countryLocationId` (an admin-0 location id) to SCOPE the
refresh to that country's subtree — only that country's buckets are
(re)computed (the window's reports are still scanned; the bucket step
filters to scopes whose admin-0 ancestor is this country). Omit it to
refresh every country in the window (the original global behaviour).
The per-country partitioned pipeline passes it so each country's run
recomputes only its own buckets instead of a redundant global pass.
An unresolvable id errors rather than silently computing nothing.
Upload a PDF into the manual-ingest S3 inbox and trigger the
Dagster `process_manual_document_job` to run the extract →
chunk → enrich → embed → upsert chain against it.
The report_id is derived from the file's SHA-256 (first 12 chars,
prefixed `manual:`) so re-uploading the same bytes is idempotent
— Dagster runs but the upsert path replaces the previous version
in place. To force a fresh row, tweak the file (any byte) or
switch to a scripted upload that supplies its own report_id.
Restricted to admin / analyst — the ingest costs LLM + embedding
credits per document. When DAGSTER_URL is unset the mutation
still stages the PDF in S3 but returns a UNKNOWN-status job with
no runId — useful for offline dev of the upload path.
Create a ground source — the per-source policy record (consent
scope, privacy default, reviewer roles, retention) that every ingest
from a WhatsApp group or hotline is gated on. Admin only; group
kinds require a complete consent record (consentScope +
consentRecordedAt + consentRecordedBy).
input: CreateGroundSourceInput!
updateGroundSource
GroundSource!
Update a source's policy record (admin only, partial). The merged
row is re-validated — a group-kind source cannot be left without a
complete consent record, so legacy rows must have consent supplied
in the same update. transportId is immutable.
id: String!input: UpdateGroundSourceInput!
setGroundSourceActive
GroundSource!
Activate or deactivate a source (admin only). Deactivation is the
live-capture kill switch: the ingest consent gate rejects every
payload for an inactive source. Deliberately exempt from
consent-record validation so an incomplete legacy row can still be
shut off immediately.
id: String!isActive: Boolean!
reviewGroundThread
GroundThread!
Review a ground thread: decision is "approve_private",
"approve_public", or "reject". Role-gated per source (the caller's
global role must appear in the source's reviewerRoles; platform
admins always pass). Transitions follow the V1 state machine —
notably approved_public is terminal. approve_public also promotes
the thread into the standard signals graph via createSignal, with
all sender identity scrubbed.
`overrides` (approve_public only) carries the reviewer's edits into
the promoted signal. `rejectReason` (reject only) is one of "spam",
"not_report", "unusable", "duplicate"; any other decision clears it.
Either one sent with the wrong decision is BAD_USER_INPUT.
PIPELINE CONTRACT (admin/pipeline only): write back
classifications from the classify_ground_messages worker. Unknown
messageIds are skipped with a warning. Returns the number of
messages updated.
inputs: [GroundMessageClassificationInput!]!
upsertGroundMessageTranscripts
Int!
PIPELINE CONTRACT (admin/pipeline only): write back transcriptions
from the ground_transcribe worker. Unknown messageIds are skipped
with a warning. Returns the number of messages updated.
inputs: [GroundMessageTranscriptInput!]!
upsertGroundThreads
[String]!
PIPELINE CONTRACT (admin/pipeline only): replace placeholder
threading with pipeline-built threads (clusters of staged
Signals). Each input creates a
thread (or, when `threadId` is set, APPENDS to that existing
thread and updates its lifecycleState + title), re-points its
messageIds at it, and deletes the placeholder threads that became
empty. Messages whose current thread has already been human-reviewed
(or promoted) are NEVER re-threaded, and a promoted `threadId`
target is never mutated (a new thread is created instead) — the
review gate outranks the pipeline. Returns one thread id per input,
in order; null where an input had no movable messages (no thread
created or updated).
inputs: [GroundThreadUpsertInput!]!
upsertGroundThreadDrafts
Int!
PIPELINE CONTRACT (admin/pipeline only): write back enrichment
drafts (title/severity/location/disasterType) from the hotline
enrichment job. Unknown threadIds are skipped with a warning. Null
fields on an input leave the existing draft value unchanged. Returns
the number of threads updated.
inputs: [GroundThreadDraftInput!]!
markGroundMessagesFailed
Int!
PIPELINE CONTRACT (admin/pipeline only): durably mark messages a
ground drain has given up on (attempts exhausted, or a message that
can never succeed). A marked message drops out of that stage's queue
in groundMessagesForClassification until retryGroundMessage clears
it. A message whose stage already succeeded (classification /
transcript set) is left unmarked. Unknown messageIds are skipped with
a warning. Returns the number of messages marked.
inputs: [GroundMessageFailureInput!]!
retryGroundMessage
GroundMessage!
Clear a message's failure marker for one stage (admin/analyst), so
it re-enters that drain's queue on the next pipeline run. No-op when
the stage isn't marked failed. Returns the message.
messageId: String!stage: GroundPipelineStage!
requestGroundMessageTranslation
GroundMessageTranslation!
Translate one staged message's text into `locale` (admin/analyst)
— any supported locale, `en` included (the source is the reporter's
language). Queues it for the pipeline's translate drain and returns the
current state; poll GroundMessage.translation(locale) while queued.
Idempotent: a ready translation is returned as is, a queued one keeps
its place, and a request after the drain gave up queues it again. A
message with no text is unavailable. The message's own text is never
changed.
messageId: String!locale: String!
createWebhookSubscription
WebhookSubscription!
Create a new webhook subscription. The response is the only place
the plaintext secret is returned — persist it in your own records
(e.g. downstream verifier config) at this moment. To retrieve later,
use rotateWebhookSubscriptionSecret which generates a fresh one.
input: CreateWebhookSubscriptionInput!
updateWebhookSubscription
WebhookSubscription!
Update a subscription. Only provide fields you want to change.
id: String!input: UpdateWebhookSubscriptionInput!
deleteWebhookSubscription
Boolean!
Permanently delete a subscription and all its delivery history.
id: String!
rotateWebhookSubscriptionSecret
WebhookSubscription!
Generate a new secret and invalidate the old one. Response
includes the new plaintext secret (same one-shot semantics as
create).
id: String!
sendTestWebhookEvent
WebhookDelivery!
Send a synthetic test event to this subscription. Creates a
WebhookDelivery row and attempts delivery immediately. Payload
mimics GlitchTip's alert format so downstream verifiers see a
realistic shape.
id: String!
retryWebhookDelivery
WebhookDelivery!
Re-fire a dead-lettered delivery. Resets attemptNumber to 1 and
schedules an immediate retry via the poller.
id: String!
requestEventEnrichment
[Task!]!
Request an Event enrichment. Always fans out: one Task per enabled
source kind of the `kind` family (server-configured; today
`event.impact_prior.web`, the web search that proposes signals for
analysts to review), so every Worker proposes on the Event side by side
and nothing marks it done. Returns the open (PENDING / LEASED) Task per
kind, in configured order — an already-open one is returned unchanged
rather than duplicated; only kinds with none get a new Task. Same
rights as `escalateEvent`: a global admin or analyst anywhere; a team
content writer for the `teamId` they act on behalf of. Capped per
requester per UTC day, counting requests not Tasks (FORBIDDEN with
subCode `DAILY_CAP`); a request that creates nothing does not count.
The only family today is `event.impact_prior` (a historical name: the
ImpactPrior itself is computed, see `Event.computedImpactPriors`);
`horizonYears` (default 10) is how far back each Worker looks for
cases.
eventId: String!kind: StringteamId: StringhorizonYears: Int
decideCaseProposal
CaseProposal!
Decide one web case (V4): a platform admin or analyst accepts or
rejects it, recorded as who, when and why (the Domain Ontology's
DecisionRecord). Only from `proposed` (CONFLICT otherwise). The
`rationale` is required to reject and optional to accept.
Accepting writes the case into CLEAR as history, in one transaction:
a Signal (source `web_enrichment`, `url` the case's source,
`publishedAt` the date the incident happened, submitted by the decider)
on the CLEAR Event it describes — the Worker's matched Event, else the
Event that already carries the same URL, else a new historical Event
dated to the incident. A Signal with the same URL already in CLEAR is
reused, not duplicated. Historical Events never alert: their newest
Signal is the incident's date. The case's figures become Estimates on
that Event (`media_report`, `event_caused`). The returned case carries
`resultSignalId` and `resultEventId`.
Rejecting keeps the case, so its URL is never proposed again for that
Event.
Cancel a Task. The requester or a platform admin only. A PENDING
Task is CANCELLED at once; a LEASED one is flagged and becomes
CANCELLED at the Worker's next heartbeat, completion or failure (its
result is discarded). Any other status is CONFLICT.
id: String!
claimTasks
[Task!]!
WORKER CONTRACT (`worker` role): lease up to `limit` of the
oldest claimable Tasks of exactly `kind` — PENDING, or LEASED past
their expiry — atomically (`FOR UPDATE SKIP LOCKED`), so no two
Workers hold the same Task. A Worker drains its own source kind
(`event.impact_prior.web`, …). The retired whole-prior kinds — the
bare `event.impact_prior` and `event.impact_prior.clear` — are
BAD_USER_INPUT. `limit` is
clamped to the platform cap. Each lease lasts TASK_LEASE_MINUTES;
heartbeat to keep it.
kind: String!limit: Int
heartbeatTask
Task!
WORKER CONTRACT: keep a lease alive. Extends `leaseExpiresAt` by
TASK_LEASE_MINUTES from now. Only the lease owner, only while LEASED
(CONFLICT `NOT_LEASED`, FORBIDDEN `NOT_LEASE_OWNER` — the latter
means the lease lapsed and was reclaimed, so this `leaseToken` is
stale; stop working on it). If cancellation was requested, the Task becomes
CANCELLED and the Worker should stop.
id: String!leaseToken: String!
failTask
Task!
WORKER CONTRACT: give the Task up with an error. It returns to
PENDING for another Worker (or attempt) while attempts remain, and
becomes FAILED with this as its `lastError` once `maxAttempts`
claims have been used. Only the lease owner, only while LEASED.
id: String!leaseToken: String!error: String!
completeTask
Task!
WORKER CONTRACT: report the Task done. `result` is the raw output
(audit only). For an `event.impact_prior.web` Task, pass `cases`
and `methodVersion` (V4): one CaseProposal per case, each decided on
its own (outcome `produced`); a URL already proposed for the Event is
skipped (`no_new_cases` when all were); an empty list or none records
`no_prior_found`. Any other kind completes with `result` only. The
whole-prior `impactPrior` input was removed (2026-10-08): the
ImpactPrior is computed from history. Only the lease owner,
only while LEASED (CONFLICT
`NOT_LEASED`, FORBIDDEN `NOT_LEASE_OWNER`). If cancellation was
requested meanwhile the Task becomes CANCELLED and the result is
discarded.
id: String!leaseToken: String!result: JSON!usage: TaskUsageInputcases: [CaseProposalInput!]methodVersion: String — Skill or handler version that produced `cases`; required with them.
Types
All types in the schema, auto-generated from the running server.
DateTimescalar
ISO 8601 date-time string (e.g. 2024-01-15T09:30:00.000Z).
GeoJSONscalar
JSONscalar
Arbitrary JSON value — objects, arrays, strings, numbers, booleans, or null.
Uploadscalar
File upload scalar (via graphql-upload).
AlertOrderByenum
Value
Description
CREATED_DESC
Newest first by event.firstSignalCreatedAt.
CREATED_ASC
Oldest first by event.firstSignalCreatedAt.
SEVERITY_DESC
Highest event severity first.
SEVERITY_ASC
Lowest event severity first.
AlertStatusenum
Publication status of an alert.
Value
Description
draft
—
published
—
archived
—
AnalysisRequestStatusenum
Value
Description
PENDING
—
GENERATED
—
FAILED
—
CaseProposalDecisionenum
The decision a named admin or analyst records on a proposed case.
Value
Description
accepted
—
rejected
—
CaseProposalStateenum
A web Worker writes `proposed` only (V4). A named admin or analyst
accepts or rejects each case; a rejected one stays, so its URL is never
proposed again for the same Event.
Value
Description
proposed
—
accepted
—
rejected
—
Channelenum
Notification channel for alert subscriptions.
Value
Description
email
—
sms
—
CrisisEnrichmentStatusenum
Durable enrichment status for the Dagster drain. PENDING = needs
(re)enrichment (set on crisis create / event add / event remove);
ENRICHED = narrative/scenarios/needs-analysis current.
Value
Description
PENDING
—
ENRICHED
—
DetectionStatusenum
Processing status of a detection (retained for potential future use).
Value
Description
raw
—
processed
—
ignored
—
EntityKindenum
Value
Description
signal
—
event
—
alert
—
EstimateAttributionenum
Whether a figure counts need caused by the Event, need that existed
beforehand, or both.
Value
Description
event_caused
—
pre_existing
—
combined
—
EstimateMethodenum
How a figure was arrived at (the Domain Ontology's Estimate methods).
`not_documented` when the method is unknown, e.g. figures backfilled from
the pipeline's Event fields.
Value
Description
exposure_model
—
model_inference
—
rapid_assessment
—
formal_assessment
—
registration
—
field_staff_judgement
—
partner_or_cluster_figure
—
prior_caseload_analogue
—
government_figure
—
media_report
—
not_documented
—
EstimateMetricenum
Which of the seven distinct figures an Estimate is (the Domain
Ontology's Metric types). The sector routinely conflates them; keeping
them apart is the point.
Value
Description
people_affected
—
people_displaced_new
—
people_displaced_cumulative
—
people_in_need
—
people_targeted
—
people_reached
—
households_affected
—
EventOrderByenum
Value
Description
LAST_SIGNAL_DESC
Newest signal first (lastSignalCreatedAt).
LAST_SIGNAL_ASC
Oldest signal first (lastSignalCreatedAt).
CREATED_DESC
Newest first by firstSignalCreatedAt.
CREATED_ASC
Oldest first by firstSignalCreatedAt.
SEVERITY_DESC
—
SEVERITY_ASC
—
Frequencyenum
How often a user receives alert notifications.
Value
Description
immediately
—
daily
—
weekly
—
monthly
—
GlobalRoleenum
Assignable global platform roles. `pending` is not in this
enum — those users must go through `approveUser` first.
Value
Description
viewer
—
analyst
—
admin
—
GroundPipelineStageenum
A clear-pipeline ground drain stage that can give up on a message.
Requested; the pipeline's translate drain hasn't written it yet.
ready
Translated — `text` holds it.
unavailable
Not requested, nothing to translate (no text), or the drain gave
up. Requesting again re-queues it.
ImpactPriorStateenum
The state a V1–V3 whole-prior proposal was left in. Retired: none is
created or decided any more.
Value
Description
proposed
—
accepted
—
rejected
—
InvitationStatusenum
Status of an invitation.
Value
Description
pending
—
accepted
—
expired
—
KnowledgebaseIngestStatusenum
Coarse-grained status of a manual-ingest Dagster run. Dagster's
own RunStatus enum is finer-grained (STARTING / MANAGED / CANCELING
/ …) — we fold those down to what a UI actually needs to render.
Value
Description
QUEUED
—
STARTED
—
SUCCESS
—
FAILURE
—
CANCELED
—
UNKNOWN
Dagster is offline, the run id doesn't exist, or the run status
is one this API doesn't recognise. Non-terminal — poll again.
KnowledgebaseSearchModeenum
How `searchKnowledgebase` merges the report + incident tiers
(ADR-0006).
Value
Description
AUTO
Pick FRAME when the query is effectively empty / frame-only, else
TOPICAL.
FRAME
Situation-analysis: a location+time frame with little topical text.
Returns a report band + a quota-bounded incident band ordered by
recency + severity; no similarity floor (it would gate out the very
incidents the frame is asking for).
TOPICAL
Chatbot: a strong free-text query. Interleaves the two tiers by
relevance (soft), gating weak incidents below a similarity floor and
giving reports a small rank preference.
KnowledgebaseTierenum
A knowledgebase tier (ADR-0006). `report` = the ReliefWeb state/analysis
KB; `incident` = an event card from the incident index (lower-tier, possibly
unverified). Lowercase values match the stored tier strings.
Value
Description
report
—
incident
—
NotificationStatusenum
Value
Description
PENDING
—
DELIVERED
—
FAILED
—
READ
—
OrgMemberRoleenum
Role within an organisation.
Value
Description
org_admin
—
member
—
SignalOrderByenum
Value
Description
PUBLISHED_DESC
Newest first by publishedAt.
PUBLISHED_ASC
Oldest first by publishedAt.
SEVERITY_DESC
—
SEVERITY_ASC
—
SignalStatusenum
Durable processing status for the Dagster event-driven drain.
NEW = ingested, awaiting downstream processing; PROCESSED = classify→group→
alert done; FAILED = terminal failure.
Value
Description
NEW
—
PROCESSED
—
FAILED
—
StatsGroupByenum
Value
Description
none
Single bucket — just `total`. Use this for "how many X" queries.
type
Group by event/signal type (event.types[] is unnested; signals use
their source name as the type proxy).
severity
Group by integer severity (1-5).
day
Group by day / week / month of the entity's primary timestamp.
Buckets are returned with ISO-8601 keys (`YYYY-MM-DD`, `YYYY-Www`,
`YYYY-MM`).
week
—
month
—
TaskOriginenum
Who asked for the Task: a signed-in user, an automatic rule, or an
API-key caller.
Value
Description
user
—
rule
—
api
—
TaskStatusenum
Lifecycle of a Task. PENDING → LEASED (claimed) → COMPLETED | FAILED;
PENDING or LEASED → CANCELLED. An expired lease returns the Task to
PENDING lazily, at the next claim. Tasks are never deleted.
Value
Description
PENDING
—
LEASED
—
COMPLETED
—
FAILED
—
CANCELLED
—
TeamMemberRoleenum
Role within a team.
Value
Description
team_admin
—
field_coordinator
—
emergency_response_manager
—
team_member
—
WebhookDeliveryStatusenum
Value
Description
pending
Waiting for the first attempt (rare — the receive route usually attempts inline).
succeeded
Delivered — target returned 2xx on some attempt.
retrying
Failed at least once; a retry is scheduled.
dead
Exhausted all retry attempts. Admin can manually re-fire.
AcceptInviteInputinput
Field
Type
Description
token
String!
—
name
String!
—
password
String!
—
ActivityLogFilterInputinput
Filter for the paginated activityLogs query.
Field
Type
Description
userId
String
—
actionPrefix
String
Action prefix match — e.g. 'crisis.' returns all crisis-related rows.
Provide exactly one of eventId, signalId, or crisisId.
signalId
String
—
crisisId
String
—
comment
String!
—
tagUserIds
[String!]
User IDs to tag in the comment.
AddFeedbackInputinput
Field
Type
Description
eventId
String
Provide exactly one of eventId, signalId, or crisisId.
signalId
String
—
crisisId
String
—
rating
Int!
Rating from 1 to 5.
text
String
Optional textual feedback.
AlertDigestInputinput
Field
Type
Description
alertIds
[String!]!
List of alert IDs to include in the digest.
frequency
String!
Frequency: daily, weekly, or monthly.
AlertNotifyInputinput
Field
Type
Description
alertId
String!
Alert ID to notify subscribers about (uses immediate frequency).
AlertsPageInputinput
Field
Type
Description
limit
Int
Page size — clamped to [1, 100]. Default 25.
offset
Int
Zero-based row offset. Default 0.
orderBy
AlertOrderBy
—
status
AlertStatus
—
teamId
String
Apply a team's location-scope filter to the underlying events.
locationId
String
Restrict to alerts whose event sits under this location (or any of
its descendants).
eventTypes
[String!]
Glide codes — alert event must contain at least one of these in its
`types` array. Case-sensitive.
severityMin
Int
Inclusive lower bound on event severity (1-5).
severityMax
Int
Inclusive upper bound on event severity (1-5).
from
DateTime
Filter on event.firstSignalCreatedAt — inclusive.
to
DateTime
Filter on event.firstSignalCreatedAt — inclusive.
includeDummy
Boolean
Hide isDummy events when false (default).
AnalysisFrameInputinput
A frame — the scope of an analysis. `windowEnd` omitted / null means
rolling "to present". Array members are order-insensitive (canonicalised
server-side).
Field
Type
Description
locationIds
[String!]
—
eventTypes
[String!]
—
needSectors
[String!]
—
windowStart
DateTime!
—
windowEnd
DateTime
—
CaseFigureInputinput
One figure a case's source gives.
Field
Type
Description
metric
String!
One of `people_affected`, `people_displaced_new`,
`people_displaced_cumulative`, `people_in_need`, `people_targeted`,
`people_reached`, `households_affected`.
value
Float!
Non-negative. With bounds, `lowerBound ≤ value ≤ upperBound`.
lowerBound
Float
—
upperBound
Float
—
unit
String
—
populationGroup
String
—
CaseProposalInputinput
One case a web Worker proposes on completing an
`event.impact_prior.web` Task (V4).
Field
Type
Description
sourceUrl
String!
Absolute http(s) URL; one case per URL per Event.
quote
String!
The source's own words, verbatim.
occurredAt
DateTime!
When the incident happened: within the request's horizon, not in the future.
locationLabel
String!
—
locationId
String
A CLEAR location in the Event's country, if resolved.
hazardType
String!
Must be one of the Event's `types`.
geographicScope
String!
`district` or `country`.
figures
[CaseFigureInput!]
—
matchedEventId
String
The CLEAR Event this case describes, if the Worker found one: it must
exist, not be the Event being enriched, manifest the case's hazard and
sit in the same country.
ConversationMessageInputinput
One message to create or replace, matched by id.
Field
Type
Description
id
String!
The Agent's message id. Rejected if it belongs to another Conversation.
role
String!
`user`, `assistant`, `system`, `tool` or `signal`.
type
String
—
content
JSON!
The message parts. At most 1,000,000 characters as JSON.
currentView
JSON
User turns: the Current view (page, entity ids, filters — identifiers,
never data), at most 10,000 characters as JSON. Omit on update to keep it.
createdAt
DateTime
Ordering key for history. Defaults to now on create; omit on update to keep it.
ConversationTurnUsageInputinput
What one CLEAR Agent turn used. Recorded on its Answer.
Field
Type
Description
model
String!
The model id the turn ran on, e.g. `anthropic/claude-sonnet-5-5`.
inputTokens
Int!
—
outputTokens
Int!
—
costUsd
Float!
Cost in USD, computed by the caller from its price table.
latencyMs
Int!
—
CreateAlertInputinput
Field
Type
Description
eventId
String!
The event ID to create an alert from.
status
AlertStatus
—
CreateAnalysisAutomationInputinput
Field
Type
Description
locationIds
[String!]
—
eventTypes
[String!]
—
needSectors
[String!]
—
windowStart
DateTime!
—
cadence
String!
Refresh cadence label, e.g. `daily` / `weekly`.
teamId
String
Owning team. Omit for a system-owned automation (admin only).
CreateApiKeyInputinput
Input for creating a new API key.
Field
Type
Description
name
String!
A descriptive name for this key (e.g. my-app-prod).
expiresAt
DateTime
Optional expiration date. Omit for a key that never expires.
CreateBulkNotificationsInputinput
Field
Type
Description
userIds
[String!]!
List of user IDs to notify.
message
String!
—
notificationType
String!
—
actionUrl
String
—
actionText
String
—
CreateCrisisFromEventsInputinput
Field
Type
Description
title
String
—
summary
String
—
severity
Float!
—
locationId
String
—
needs
JSON!
Needs as JSON.
eventIds
[String!]!
Event IDs to link to the newly created crisis (must not be empty).
teamId
String
Team the crisis is being filed under. When present, the caller may be
a team-level team_admin or field_coordinator on that team instead of a
platform admin/analyst. Purely an authorisation hint — the crisis itself
has no team column; team affiliation is derived from location scope.
Ignored for platform-level callers.
CreateDataSourceInputinput
Field
Type
Description
name
String!
—
type
String!
—
isActive
Boolean
—
baseUrl
String
—
infoUrl
String
—
synonyms
[String!]
Alias set for source-name normalisation (see resolveDataSource).
reliability
Int
NATO Admiralty-style reliability grade 1–4; null = ungraded.
CreateDevUserInputinput
Input for `createDevUser`.
Field
Type
Description
email
String!
The dev's email address — also the dedup key against existing users.
name
String!
Display name shown in the welcome email and in the User row.
keyName
String
Optional descriptive label for the first API key. Defaults to "Initial dev key".
CreateEventInputinput
Field
Type
Description
signalIds
[String!]!
—
title
String
—
description
String
—
descriptionSignals
JSON
—
validFrom
String!
—
validTo
String
—
firstSignalCreatedAt
String!
—
lastSignalCreatedAt
String!
—
startedAt
String
When the real-world event started (onset), parsed from signal text.
ISO-8601; null/omitted when no onset could be resolved.
originId
String
—
destinationId
String
—
locationId
String
—
types
[String!]!
—
severity
Int
Severity score (1–5). Aggregated from signal severities.
populationAffected
String
—
populationDisplaced
String
Estimated population displaced (BigInt as string).
casualties
Int
Aggregated casualties for the event (max across constituent signals).
rank
Float!
—
lat
Float
Latitude for automatic geo-resolution (resolves to nearest location in hierarchy).
lng
Float
Longitude for automatic geo-resolution.
teamId
String
Team the event is being filed under. When present, the caller may be
a team-level team_admin or field_coordinator on that team instead of a
platform admin/analyst. Purely an authorisation hint — the event itself
has no team column; team affiliation is derived from location scope.
Ignored for platform-level callers.
CreateGroundSourceInputinput
Field
Type
Description
name
String!
—
kind
String!
"staff_group" | "partner_group" | "hotline".
transportId
String!
WhatsApp group JID (or hotline number). Must be unique.
consentScope
String
REQUIRED (with consentRecordedAt + consentRecordedBy) for the
group kinds; hotline consent is explicit by design.
consentRecordedAt
String
—
consentRecordedBy
String
—
privacyDefault
String
Defaults to "private".
reviewerRoles
[String!]
Defaults to ["admin", "analyst"].
retentionRule
String
—
CreateLocationInputinput
Field
Type
Description
geoId
Int
—
osmId
String
—
pCode
String
—
name
String!
—
level
Int!
—
parentId
String
—
CreateManualSignalInputinput
Field
Type
Description
sourceId
String!
Data source ID (must be field_officer, partner, or government type).
title
String!
—
description
String!
—
severity
Int
Severity score (1–5).
url
String
URL or reference link.
mediaUrls
[String!]
Media URLs (pre-uploaded via /api/upload endpoint).
media
[Upload!]
Media files (direct upload via graphql-upload, alternative to mediaUrls).
locationId
String
—
originId
String
—
destinationId
String
—
lat
Float
Latitude for automatic geo-resolution.
lng
Float
Longitude for automatic geo-resolution.
metadata
JSON
Arbitrary internal metadata stored in rawData (e.g. notes, recommendAlert).
Not surfaced in the UI - use freely without schema changes.
teamId
String
Team the signal is being filed under. When present, the caller may be
a team-level team_admin or field_coordinator on that team instead of a
platform admin/analyst. Purely an authorisation hint — the signal itself
has no team column; team affiliation is derived from location scope.
Ignored for platform-level callers.
CreateNotificationInputinput
Field
Type
Description
userId
String!
—
message
String!
—
notificationType
String!
—
actionUrl
String
—
actionText
String
—
CreateOrganisationInputinput
Fields for creating a new organisation.
Field
Type
Description
name
String!
Display name for the organisation.
slug
String!
URL-friendly identifier. Must be unique.
CreatePublicEventLinkInputinput
Input for the `createPublicEventLink` mutation.
Field
Type
Description
eventId
String!
The event to share. Caller must be able to read it via the
normal `event(id)` resolver — i.e. `requireContentReader`
passes.
ttlDays
Int
Snapshot lifetime in days. Defaults to 30, capped at 90. Smaller
values produce shorter URLs by reducing the impact of any future
URL-history scraping.
CreateSignalInputinput
Field
Type
Description
sourceId
String!
—
externalId
String
Stable upstream identifier for idempotent ingestion. If a signal with
the same (sourceId, externalId) already exists, createSignal returns the
existing row instead of creating a duplicate. Recommended prefix scheme:
"dataminr:{alertId}", "gdacs:{eventid}", "acled:{event_id_cnty}".
contentHash
String
Fingerprint of rawData, for sources whose records get revised in
place (e.g. IDMC). Optional — most sources never revise a signal after
creation, so this stays null for them. Seeding it here means an
immediate follow-up updateSignalContent call (same hash) is a correct
no-op instead of falsely stamping lastRevisedAt on a brand-new signal.
rawData
JSON!
Write-only ingest payload stored internally. Not exposed on Signal queries.
rawS3Key
String
Pointer to the raw payload blob in the S3 data lake (bronze layer),
written by the Dagster ingest asset. Optional — rawData carries the payload
for sources not yet landing in the lake.
publishedAt
String!
—
collectedAt
String
—
url
String
—
title
String
—
description
String
—
severity
Int
Severity score (1–5). From data source or estimated by pipeline.
casualties
Int
Reported casualties for the signal.
media
[String!]
Media URLs (source URLs for images, videos, etc.).
originId
String
—
destinationId
String
—
locationId
String
—
lat
Float
Latitude for automatic geo-resolution (resolves to nearest location in hierarchy).
lng
Float
Longitude for automatic geo-resolution.
geoparsedData
JSON
Optional output of clear-pipeline's text-based geoparser. Additive
enrichment, stored verbatim for downstream comparison against the
source's coords. Schema documented on the signals model.
pointName
String
Human-readable name to use when the resolver has to create a new L4
point location from `lat`/`lng`. Typically the geoparser's
top extracted candidate suffixed with " (unresolved)" when the
Nominatim lookup failed, so audit views show `al-Obeid (unresolved)`
instead of the signal's full paragraph. Ignored when `locationId`
is supplied. When omitted, the resolver falls back to a coord-based
label like `Point 15.6280, 30.2156`.
CreateTeamInputinput
Field
Type
Description
organisationId
String!
—
name
String!
—
slug
String!
—
description
String
—
CreateWebhookSubscriptionInputinput
Input for creating a new webhook subscription. The secret is
generated server-side (openssl rand -hex 32 equivalent) and returned
once on create.
Field
Type
Description
name
String!
—
targetUrl
String!
—
eventTypeFilter
[String!]
Empty array = fire on all events. Otherwise, only fire when the
source payload's event type matches one of these values.
active
Boolean
Whether the subscription starts active. Defaults to true.
DateRangeInputinput
Half-open date window (from inclusive, to exclusive) used to
filter `searchKnowledgebase` by the chunk's extracted event
window. Chunks whose time_range overlaps the window match.
Field
Type
Description
from
DateTime
—
to
DateTime
—
EntityStatsInputinput
Field
Type
Description
entity
EntityKind!
—
groupBy
StatsGroupBy
—
teamId
String
—
locationId
String
—
eventTypes
[String!]
—
severityMin
Int
—
severityMax
Int
—
from
DateTime
—
to
DateTime
—
includeDummy
Boolean
—
EventsPageInputinput
Field
Type
Description
limit
Int
—
offset
Int
—
orderBy
EventOrderBy
—
teamId
String
—
locationId
String
—
eventTypes
[String!]
—
severityMin
Int
—
severityMax
Int
—
from
DateTime
Filter on event.firstSignalCreatedAt — inclusive.
to
DateTime
—
includeDummy
Boolean
—
FindOrCreateLandmarkL4Inputinput
Input for findOrCreateLandmarkL4. Drives geoparser-based L4 promotion
in the signal-ingestion pipeline.
Field
Type
Description
name
String!
Display name to use when creating a new L4 (e.g., 'Nyala Airport').
Reuse for kind='landmark' is keyed on a case-insensitive match of this
field within the candidate's containing A2.
lat
Float!
Candidate latitude (from the geocoder).
lng
Float!
Candidate longitude (from the geocoder).
kind
String!
'landmark' or 'admin'. Drives the reuse strategy: landmarks reuse by
exact name, admins reuse by proximity (≤100m) within the same A2.
sourceLat
Float
Source coordinate's latitude. When provided, the resolver verifies the
candidate's A2 matches the source's A2 — a mismatch aborts the promotion.
sourceLng
Float
Source coordinate's longitude. See sourceLat.
GroundMessageClassificationInputinput
One classification write-back from the pipeline worker.
Pipeline-detected uncertainty tag. Null/omitted leaves the
ingest-extracted marker untouched.
GroundMessageFailureInputinput
One failure marker from a clear-pipeline ground drain.
Field
Type
Description
messageId
String!
—
stage
GroundPipelineStage!
—
error
String!
Exception text from the last attempt. Stored truncated to 500
characters, with phone numbers redacted.
GroundMessageTranscriptInputinput
One transcription write-back from the ground_transcribe worker.
Field
Type
Description
messageId
String!
—
transcript
String!
Transcribed text of the message's voice note(s).
GroundPromotionOverridesInputinput
Reviewer edits applied to the signal a thread is promoted into
(reviewGroundThread approve_public only). Omitted, null or blank fields
keep the default derived from the thread (thread title; the joined
message text as description; no severity; no location). The signal's
rawData provenance is never affected.
Field
Type
Description
title
String
—
description
String
—
severity
Int
Integer 1-5.
locationId
String
An existing `locations` row id (any admin level).
GroundThreadDraftInputinput
One enrichment draft from the Dagster hotline-enrichment job. Null
fields leave the existing draft value on the thread unchanged.
Field
Type
Description
threadId
String!
—
draftTitle
String
—
draftSeverity
Int
1-5. Validated server-side when present.
draftLocationId
String
—
draftDisasterType
String
—
GroundThreadUpsertInputinput
One thread (a cluster of staged Signals) produced by the pipeline
threading task. Its messageIds are re-pointed at the thread, replacing
their V1 one-per-message placeholder threads. With `threadId` set,
the input APPENDS to that existing thread (cross-run threading: late
corrections/retractions join the thread they belong to) instead of
creating a new one.
Optional target thread for cross-run appends. When set, messageIds
are appended to this thread and its lifecycleState + title are
updated — provided the thread is not yet promoted (reviewState !=
"approved_public" and no promotedSignalId) and belongs to
groundSourceId. A promoted/terminal (or unknown/wrong-source) target
is never mutated: a NEW thread is created instead, with a warning.
InviteUserInputinput
Field
Type
Description
email
String!
—
organisationId
String!
—
role
String
Organisation role: org_admin, member (default: member).
teams
[TeamAssignmentInput!]!
Team assignments — at least one team is required. Each entry grants the
invitee membership in that team with the given role on acceptance.
KnowledgebaseChunkInputinput
One chunk written into the knowledgebase table. Mirrors the
columns exactly (minus `lexicalTsv`, which the DB trigger fills
from `embeddedText`, and `createdAt` which uses the column
default).
Field
Type
Description
chunkIndex
Int!
0-indexed position within the report.
pageStart
Int!
Inclusive PDF page span this chunk covers.
pageEnd
Int!
—
chunkText
String!
Raw excerpt text — what a UI would render on a search hit.
contextPrefix
String!
LLM-generated context prefix (empty string when contextualization
is skipped).
embeddedText
String!
`contextPrefix + "\n\n" + chunkText` — what was actually
embedded and tokenised.
embeddingProvider
String!
Provenance for the embedding — mirrors the DB columns so a
later re-embed backfill can filter by (provider, model).
embeddingModel
String!
—
embedding
[Float!]!
1024-dim dense embedding. The API validates length and casts to
`vector(1024)` before insert.
locationIds
[String!]!
Resolved `locations.id` refs (post-lookup).
locationPcodes
[String!]!
Raw pcodes the LLM emitted but the resolver couldn't match.
timeRangeStart
DateTime
Optional event window described by the chunk.
timeRangeEnd
DateTime
—
eventTypes
[String!]!
Multi-hazard tags — GLIDE codes or free-text categories.
needSectors
[String!]!
NRC SAF sectors: Shelter, WASH, Protection, Health,
Food Security, Education.
figureS3Key
String
Infographic capture: set only when this chunk is a figure
transcription merged into the KB. `figureS3Key` is the cropped
image's S3 key (join key to `report_figures`); `figureKind` is
that figure's kind. Both null for ordinary text chunks.
figureKind
String
—
KnowledgebaseFiltersinput
Optional filters applied BEFORE the retrieval step — array
filters use overlap semantics (any-of), the time range uses
inclusive intersection. Leave a field null to skip that filter.
Field
Type
Description
locationIds
[String!]
Match rows tagged with ANY of these `locations.id` values.
countryLocationId
String
Scope to one country: keep only chunks tagged with a location in this
A0's subtree (itself or any descendant admin unit). Chunk locations are
resolved to leaf admin ids, so a bare `locationIds=[A0]` would miss them —
this expands the A0 to its subtree server-side via the locations tree. The
situation-analysis RAG uses this so a country's analysis never cites reports
about another country.
eventTypes
[String!]
Match rows tagged with ANY of these event-type tags.
needSectors
[String!]
Match rows tagged with ANY of these SAF sectors.
timeRange
DateRangeInput
Match rows whose extracted event window overlaps this range.
currentEmbeddingModelOnly
Boolean
Restrict to rows written by the currently-configured
embedding provider + model. Default true — mixing embedding
spaces yields meaningless distances. Set false only when
inspecting historical rows via BM25-only search (no vector
step will be run for filtered-out rows).
LocaleTranslationInputinput
Per-locale payload accepted by upsertTranslations. data mirrors the
canonical entity's JSON shape exactly for the given locale — e.g. for
a crisis it carries the localized title/summary/scenarios/needs with
the same keys/nesting the English columns use.
Field
Type
Description
locale
String!
BCP-47 lowercased — 'ar', 'fr'. 'en' is rejected (canonical) except
for groundMessage, whose source is the reporter's language.
data
JSON!
Translated payload. Shape mirrors the canonical entity per type.
sourceHashes
JSON!
Per-field SHA-256 hashes of the canonical English source used to produce `data`. Stored so the pipeline can detect which canonical field changed and re-translate only that field on the next pass.
ReplyToCommentInputinput
Field
Type
Description
repliedToCommentId
String!
ID of the comment to reply to.
comment
String!
—
tagUserIds
[String!]
User IDs to tag in the reply.
ReportFigureInputinput
Field
Type
Description
pageNumber
Int!
—
bbox
[Float!]
—
isFullPage
Boolean
—
s3Key
String!
—
kind
String!
—
title
String
—
description
String
—
transcription
JSON
—
sourceId
String
—
locationIds
[String!]
—
locationPcodes
[String!]
—
eventTypes
[String!]
—
needSectors
[String!]
—
timeRangeStart
DateTime
—
timeRangeEnd
DateTime
—
RequestAnalysisInputinput
Field
Type
Description
locationIds
[String!]
—
eventTypes
[String!]
—
needSectors
[String!]
—
windowStart
DateTime!
—
windowEnd
DateTime
—
teamId
String
Owning team, for a team-scoped on-demand request.
force
Boolean
Force a regeneration past the 24h floor + freshness gate (ADR-0008).
Admin only — a non-admin passing `true` is rejected.
SaveAgentWorkingMemoryInputinput
Replace your Agent working memory. Omitted fields stay unchanged.
Field
Type
Description
workingMemory
String
The working-memory document (Markdown, at most 100,000 characters).
metadata
JSON
—
SignalsPageInputinput
Field
Type
Description
limit
Int
—
offset
Int
—
orderBy
SignalOrderBy
—
teamId
String
—
locationId
String
—
sourceNames
[String!]
Restrict to signals whose source name is in this list (e.g. ["acled","dataminr"]).
severityMin
Int
—
severityMax
Int
—
from
DateTime
Filter on signal.publishedAt — inclusive.
to
DateTime
—
includeDummy
Boolean
—
SubmitSignalLocationChallengeInputinput
Field
Type
Description
signalId
String!
—
note
String
—
proposedLng
Float
Omit both to file a bare challenge. Provide both (finite, in range) for a
Location correction — one without the other is rejected.
proposedLat
Float
—
proposedName
String
—
SubscribeToAlertsBatchInputinput
Field
Type
Description
locationIds
[String!]!
One or more location IDs.
alertTypes
[String!]!
One or more disaster/event types (glideNumbers). A subscription is created for every (location × alertType) pair.
channel
Channel!
—
frequency
Frequency!
—
minSeverity
Int
Minimum event severity (1-5). Applied to all created subscriptions.
SubscribeToAlertsInputinput
Field
Type
Description
locationId
String!
—
alertType
String!
Disaster/event type (glideNumber from disaster_types, e.g. 'fl', 'eq').
channel
Channel!
—
frequency
Frequency!
—
minSeverity
Int
Minimum event severity (1-5) to notify on. Defaults to 1 (all alerts).
TaskUsageInputinput
Spend a Worker reports when completing a Task. Cost is computed by the
caller from its own price table.
Field
Type
Description
model
String!
—
inputTokens
Int!
—
outputTokens
Int!
—
costUsd
Float!
—
TeamAssignmentInputinput
One (team, role) assignment passed to inviteUser.
Field
Type
Description
teamId
String!
—
teamRole
TeamMemberRole!
—
UpdateAlertInputinput
Field
Type
Description
status
AlertStatus
—
UpdateAlertSubscriptionInputinput
Field
Type
Description
channel
Channel
—
frequency
Frequency
—
active
Boolean
—
minSeverity
Int
Minimum event severity (1-5).
UpdateAnalysisAutomationInputinput
Field
Type
Description
cadence
String
—
enabled
Boolean
—
UpdateCrisisPopulationInputinput
Field
Type
Description
populationAffected
String
Population directly affected by the events (BigInt as string).
populationInArea
String
Total population residing within the event admin areas (BigInt as string).
Alias set for source-name normalisation (see resolveDataSource).
reliability
Int
NATO Admiralty-style reliability grade 1–4; null = ungraded.
UpdateEventInputinput
Field
Type
Description
signalIds
[String!]
—
title
String
—
description
String
—
descriptionSignals
JSON
—
validFrom
String
—
validTo
String
ISO-8601 event end. Pass `null` to clear it ("ongoing / no known end");
omit it to leave the stored value unchanged.
firstSignalCreatedAt
String
ISO-8601. Only ever moves earlier: a value later than the stored one is
ignored.
lastSignalCreatedAt
String
ISO-8601. Only ever moves later: a value earlier than the stored one is
ignored, so an out-of-order signal can't pull it back.
startedAt
String
When the real-world event started (onset), parsed from signal text.
ISO-8601. The pipeline keeps the EARLIEST onset across an event's signals.
originId
String
—
destinationId
String
—
locationId
String
—
types
[String!]
—
severity
Int
—
populationAffected
String
—
populationDisplaced
String
Estimated population displaced (BigInt as string).
casualties
Int
Aggregated casualties for the event (max across constituent signals).
rank
Float
—
UpdateGroundSourceInputinput
Partial update of a source's policy record. Null/omitted fields are
left unchanged; transportId is immutable (it is the identity that
externalIds are minted against). The merged row is re-validated: group
kinds must end up with a complete consent record.
Field
Type
Description
name
String
—
kind
String
"staff_group" | "partner_group" | "hotline".
consentScope
String
—
consentRecordedAt
String
—
consentRecordedBy
String
—
privacyDefault
String
—
reviewerRoles
[String!]
—
retentionRule
String
—
UpdateLocationInputinput
Field
Type
Description
geoId
Int
—
osmId
String
—
pCode
String
—
name
String
—
level
Int
—
parentId
String
—
UpdateOrganisationInputinput
Fields for updating an existing organisation.
Field
Type
Description
name
String
New display name.
slug
String
New URL-friendly identifier.
isActive
Boolean
Set active/inactive status.
UpdateProfileInputinput
Field
Type
Description
name
String
—
phoneNumber
String
—
image
String
—
enableInAppNotification
Boolean
—
enableEmailNotification
Boolean
—
enableSMSNotification
Boolean
—
language
String
Preferred UI language code (BCP-47 / ISO 639-1, e.g. "en", "ar").
UpdateSignalContentInputinput
Field
Type
Description
id
String!
—
contentHash
String!
Fingerprint of the incoming raw payload. Compared against the
signal's stored contentHash; the write (and lastRevisedAt) only
happens when they differ.
rawData
JSON!
—
url
String
—
title
String
—
description
String
—
severity
Int
—
casualties
Int
—
originId
String
—
destinationId
String
—
locationId
String
—
lat
Float
Fallback geo-resolution, same as CreateSignalInput's lat/lng — used
when no explicit originId/destinationId/locationId resolved.
lng
Float
—
geoparsedData
JSON
—
pointName
String
—
UpdateTeamInputinput
Field
Type
Description
name
String
—
slug
String
—
description
String
—
UpdateWebhookSubscriptionInputinput
Input for updating an existing subscription. All fields are
optional — provide only what you want to change.
Field
Type
Description
name
String
—
targetUrl
String
—
eventTypeFilter
[String!]
—
active
Boolean
—
UpsertAnalysisInputinput
Field
Type
Description
locationIds
[String!]
The frame this analysis covers.
eventTypes
[String!]
—
needSectors
[String!]
—
windowStart
DateTime!
—
windowEnd
DateTime
—
data
JSON!
—
sourceReportIds
[String!]!
—
generatedByModel
String!
—
generationCostUsd
Float
—
schemaVersion
String!
—
force
Boolean
Bypass the 24h regeneration floor (ADR-0008). The pipeline sets this for
an admin-forced request. Omitted/false: a write within 24h of the current
row's `generatedAt` is a no-op that only bumps `lastSyncedAt`.
UpsertConversationInputinput
Create a Conversation with a caller-supplied id, or update its title or metadata.
Field
Type
Description
id
String!
The Agent's thread id. Rejected if it belongs to another user's Conversation.
title
String
Omit to leave the title unchanged. At most 500 characters.
metadata
JSON
Omit to leave the metadata unchanged. At most 100,000 characters as JSON.
createdAt
DateTime
Creation time from the Agent. Ignored on update. Defaults to now.
UpsertLocationMetadataInputinput
Field
Type
Description
locationId
String!
—
type
String!
Type string (e.g. "iom_dtm_displacement").
data
JSON!
JSON payload for this type.
UpsertNominatimCacheInputinput
Field
Type
Description
queryHash
String!
SHA-256 hex digest of `<endpoint>:<normalised_query>`. The caller is
responsible for computing this — the server doesn't re-hash.
query
String!
Raw query string for debugging / audit.
endpoint
String!
The Nominatim endpoint that produced this response.
responseJson
JSON!
Raw JSON response to cache. Stored verbatim.
status
String!
'ok' for a usable result, 'no_result' for an empty result set,
'error' when the geocoder returned an error response. Negative results
are cached so we don't re-ask the same dead question.
ttlSeconds
Int!
How long this entry should remain valid, in seconds. The server
computes `expires_at = NOW() + ttl_seconds`.
UpsertReportDatapointsInputinput
Input for `upsertReportDatapoints`. Field names / types
mirror the ReportDatapoint output so a client can echo one back
into the other with minimal transformation.
Field
Type
Description
reportId
String!
—
reportTitle
String!
—
sourceUrl
String!
—
publishedAt
DateTime!
—
reportingPeriodStart
DateTime
—
reportingPeriodEnd
DateTime
—
locationIds
[String!]!
—
locationPcodes
[String!]!
—
eventTypes
[String!]!
—
totalAffected
Int
—
totalDisplaced
Int
—
totalKilled
Int
—
data
JSON!
—
schemaVersion
String!
—
extractedByModel
String!
—
sourceId
String
The report's publisher source (a `data_sources` id), resolved by the
pipeline via `resolveDataSource`. Null until source attribution backfills;
a figure's own cited source lives per-figure inside `data`. See clear-pipeline ADR-0004.
UpsertReportFiguresInputinput
Replace-on-reingest payload for one report's figures (pipeline-only).
Field
Type
Description
reportId
String!
—
reportTitle
String!
—
sourceUrl
String!
—
extractedByModel
String!
—
figures
[ReportFigureInput!]!
—
UpsertSituationAnalysisInputinput
Field
Type
Description
countryLocationId
String!
—
windowStart
DateTime!
—
windowEnd
DateTime!
—
windowKind
String!
Window granularity — `yearly` today. Required: it is part of the
bucket key, so a wrong or missing value writes a row no reader will
ask for. Not defaulted, deliberately.
data
JSON!
—
sourceReportIds
[String!]!
—
aggregatedDatapointId
String
—
generatedByModel
String!
—
generationCostUsd
Float
—
schemaVersion
String!
—
UpsertTranslationsInputinput
Field
Type
Description
entityType
String!
One of 'event' | 'crisis' | 'location' | 'situationAnalysis' |
'analysis' | 'groundMessage' (case-insensitive).
entityId
String!
—
translations
[LocaleTranslationInput!]!
One entry per target locale. Each row is upserted independently.
ActivityCountsByActionobject
Field
Type
Description
login
Int!
—
signalCreateManual
Int!
—
eventCreate
Int!
—
alertCreate
Int!
—
crisisCreate
Int!
—
feedbackCreate
Int!
—
total
Int!
—
ActivityLogobject
A single user-initiated action recorded for analytics.
The created/affected row's id. Null for actions like login.
metadata
JSON
Per-action context (title, severity, etc.). Shape varies by action.
ipAddress
String
—
userAgent
String
—
createdAt
DateTime!
—
ActivityStatsobject
Aggregate counts and time-series for the admin dashboard.
Field
Type
Description
from
DateTime!
Window the stats cover, in ISO-8601. Mirrored back to the client so
a paginated dashboard can know what range its numbers are based on.
to
DateTime!
—
totals
ActivityCountsByAction!
Total event counts across the window, keyed by action.
byUser
[UserActivitySummary!]!
Per-user breakdown, ordered by total activity (desc), limited to
the top 50 most-active users in the window.
byDay
[DailyActivityCount!]!
Daily activity counts across the window (UTC dates).
AgentBudgetobject
Your daily CLEAR Agent budget. Spend is the sum of your turns' cost since
UTC midnight; the budget resets at the next UTC midnight.
Field
Type
Description
limitUsd
Float!
The daily limit in USD.
spentTodayUsd
Float!
What your turns have cost since UTC midnight, in USD.
resetsAt
DateTime!
When spend resets to zero: the next UTC midnight.
AgentWorkingMemoryobject
What the CLEAR Agent keeps about you across Threads (its working memory).
Yours only: no one else, admins included, can read or write it.
Field
Type
Description
userId
String!
—
workingMemory
String
The working-memory document (Markdown).
metadata
JSON
Opaque metadata kept by the Agent.
createdAt
DateTime!
—
updatedAt
DateTime!
—
AggregatedDatapointobject
One aggregated bucket - the roll-up of every contributing
`report_datapoint` for a scope (window × window_kind × location).
Consumed by the situation-analysis dashboard tiles and by chatbot
factual queries. See `AggregatedField` docstring for the JSON
`data` shape.
Field
Type
Description
id
String!
—
windowStart
DateTime!
—
windowEnd
DateTime!
—
windowKind
String!
One of `weekly` | `monthly` | `yearly` | `all`.
locationId
String
Null when the bucket rolls up to a country (yearly, all-time
tiers). Otherwise references `locations.id`.
data
JSON!
Flat map keyed by field label. Each value is either a
QualityEnvelope (for numeric fields), a SetUnionEnvelope (for label
fields - `{ values, contributing_report_ids }`), or `null` when
no report in scope reported that field.
A numeric QualityEnvelope carries `{ value, unit, confidence_mix,
newest_report_at, oldest_report_at, contributing_report_ids }` plus
the credibility fields (clear-pipeline ADR-0004/0005): the
cached time-invariant `reliability` (1–4) and `intrinsic_credibility`
(0–8.5), and - added on every read - `recency` (0–1.5),
`information_credibility` (0–10), and `data_quality` (**0–10**), the
per-field headline. The legacy `quality_score` (0–1, directness-only)
is retained for backwards compatibility.
contributingReportIds
[String!]!
—
newestSourceAt
DateTime!
—
oldestSourceAt
DateTime!
—
dataQualityScore
Float!
Bucket headline data quality on a **0–10** scale (clear-pipeline
ADR-0005): the mean of the fields' read-time `data_quality`
(`(reliability × 2.5 × information_credibility) / 10`, Recency folded
in at read). The stored column carries the same 0–10 scale. NOTE: this
is a scale change from the pre-data-quality `quality_score` (0–1) -
thresholds tuned on the old scale must be re-tuned.
reportCount
Int!
—
estimatedCurrentTotals
CurrentTotals
Estimated current totals - latest authoritative stock + the flows
reported after it (ADR-0006 §4). This is an **as-of-now** figure, NOT the
bucket's period: it is returned only for a bucket whose window still
includes now (the current year/month/week and the `all` tier) and is
`null` on any historical bucket, so a past-period row never carries a
present-day number. Resolved lazily - the bounded `report_datapoints` scan
runs only when this field is selected - but it is a real scan, not free.
validFrom
DateTime!
Bitemporal validity - this snapshot's lifetime as a "current"
row. `validTo` is null when the row is still the current one for
its bucket; else it carries the timestamp when a newer computation
superseded it.
validTo
DateTime
—
schemaVersion
String!
—
computedAt
DateTime!
—
onDemand
Boolean!
True when the resolver assembled this bucket on-demand from
`report_datapoints` rather than serving it from the pre-compute
cache. The dashboard can render a "just computed" indicator so
users know the number reflects the freshest possible view.
Alertobject
An alert created from an event, distributed to subscribed users.
Field
Type
Description
id
String!
—
event
Event!
The event this alert was created from.
representativePoint
Location
Location of the alert's event's FIRST signal — the same point as
`event.representativePoint`, surfaced directly on the alert so a
marker can be placed without walking into the event. Null when the
first signal has no located point. Requires any authenticated
content reader.
status
AlertStatus!
—
createdAt
DateTime!
When the alert row was first created.
updatedAt
DateTime!
Last time the alert row was updated (e.g. status transition).
userAlerts
[UserAlert!]!
Users who received this alert.
AlertsPageobject
Field
Type
Description
items
[Alert!]!
—
totalCount
Int!
—
hasMore
Boolean!
—
AlertSubscriptionobject
A user's subscription to alerts of a specific type at a specific location.
Field
Type
Description
id
String!
—
userId
String!
—
user
User!
—
location
Location!
—
alertType
String!
Disaster/event type to subscribe to (e.g. 'fl' for flood, 'eq' for earthquake).
active
Boolean!
—
minSeverity
Int!
Minimum event severity (1-5) to notify on. Alerts with event.severity < minSeverity are suppressed for this user.
channel
Channel!
—
frequency
Frequency!
—
createdAt
DateTime!
—
updatedAt
DateTime!
—
Analysisobject
A single frame-scoped analysis snapshot. Cache read path — always the
current row for its frame unless `asOf` is supplied for a historical read.
Field
Type
Description
id
String!
—
locationIds
[String!]!
── Frame ── The dimensions this analysis was generated over, the same
ones the knowledgebase is filtered by. Arrays are canonicalised (sorted +
de-duplicated) on write so frame identity is stable.
eventTypes
[String!]!
—
needSectors
[String!]!
—
windowStart
DateTime!
—
windowEnd
DateTime
Window end. `null` means rolling "to present" (an automated
analysis); a value means a fixed range (on-demand). The concrete "as of"
instant of a rolling row is `generatedAt` / `validFrom`.
data
JSON!
Full analysis blob (situation taxonomy + `scenarios`). Opaque and
versioned by `schemaVersion`; LLM components carry their own
`source_report_ids` for per-component provenance.
sourceReportIds
[String!]!
Denormalised union of every contributing report id across components.
Per-field datapoint provenance lives inside `data` — a frame can span
many aggregated-datapoints rows, so there is no single bucket reference.
generatedByModel
String!
—
generationCostUsd
Float
—
generatedAt
DateTime!
—
lastSyncedAt
DateTime
Last time any trigger checked this frame (manual sync or automation),
whether or not it regenerated (ADR-0008). On a gate skip (within the 24h
floor, or no new evidence) this advances while `generatedAt` does not.
validFrom
DateTime!
Bitemporal validity — `validTo` is null while this is the current row
for its frame, else the timestamp a regeneration superseded it.
validTo
DateTime
—
schemaVersion
String!
Bumped when the payload taxonomy or prompt set changes. Versions
coexist per frame; trend reads never mix them.
AnalysisAutomationobject
A subscription that keeps one frame's analysis current on a cadence
(ADR-0007 §5). The analysis row is shared; the scheduler regenerates each
frame at the minimum cadence across its subscribers. Automations are always
rolling ("to present"), so they carry no `windowEnd`.
Field
Type
Description
id
String!
—
locationIds
[String!]!
—
eventTypes
[String!]!
—
needSectors
[String!]!
—
windowStart
DateTime!
—
cadence
String!
—
teamId
String
—
createdByUserId
String
—
enabled
Boolean!
—
lastRunAt
DateTime
—
nextRunAt
DateTime
—
createdAt
DateTime!
—
updatedAt
DateTime!
—
AnalysisRequestobject
An on-demand analysis generation request (ADR-0007 §4). A user enqueues a
frame that may not exist yet; a pipeline sensor drains `pendingAnalyses`,
generates + upserts the analysis, and marks the request `GENERATED`. Scheduled
refreshes use `AnalysisAutomation` instead of this one-shot queue.
Field
Type
Description
id
String!
—
locationIds
[String!]!
—
eventTypes
[String!]!
—
needSectors
[String!]!
—
windowStart
DateTime!
—
windowEnd
DateTime
—
status
AnalysisRequestStatus!
—
requestedByUserId
String
—
teamId
String
—
force
Boolean!
Admin force (ADR-0008): the drain bypasses the 24h floor + freshness
check for this request.
attempts
Int!
—
lastError
String
—
createdAt
DateTime!
—
updatedAt
DateTime!
—
ApiKeyobject
A personal API key for programmatic access. The full key is only shown once at creation.
Field
Type
Description
id
String!
—
name
String!
Descriptive name you chose when creating the key.
prefix
String!
Short prefix for identification (e.g. sk_live_abc1).
expiresAt
DateTime
Optional expiration date. Expired keys are rejected automatically.
lastUsedAt
DateTime
When this key was last used to authenticate a request.
revokedAt
DateTime
When this key was revoked, if applicable. Revocation is permanent.
createdAt
DateTime!
—
updatedAt
DateTime!
—
ApproveUserResultobject
Result of the admin-only `approveUser` mutation. Flips a `pending`
user's role to `viewer` and moves the matching CRM contact from
the prospects collection into the approved collection, triggering
Exponential's welcome automation.
Field
Type
Description
user
User!
The approved user (with the new role).
crmMoved
Boolean!
True when the CRM-side list move completed cleanly. False means
the user is approved locally but the CRM record still sits in the
prospects list — the admin can retry from /portal/admin without
re-approving the user.
crmWarnings
[String!]!
Non-fatal CRM warnings, if any (e.g. profileType update failed
while the list swap succeeded). Empty on the happy path.
ArchiveStaleAlertsResultobject
Result of the archiveStaleAlerts bulk mutation.
Field
Type
Description
alertsArchived
Int!
—
CaseProposalobject
One historical case a web Worker found while enriching an Event (V4):
a past incident like it, the source that reports it, the figures it gives,
and the CLEAR Event it describes when CLEAR already holds one. The unit an
analyst accepts or rejects, one by one, in the Inbox and on the Event page.
Field
Type
Description
id
String!
—
eventId
String!
The Event whose enrichment request produced the case.
event
Event!
—
taskId
String!
—
task
Task!
—
state
CaseProposalState!
—
sourceUrl
String!
—
quote
String!
The source's own words, verbatim.
occurredAt
DateTime!
When the incident happened (valid time), not when it was reported.
locationLabel
String!
—
locationId
String
A CLEAR location for the place, when the Worker resolved one.
hazardType
String!
GLIDE code; one of the requesting Event's `types`.
geographicScope
String!
`district` or `country`: the scope the case was matched at.
figures
JSON!
The figures the source gives, each on one of the Domain Ontology's
seven metric types —
`[{ metric, value, lowerBound?, upperBound?, unit?, populationGroup? }]`.
Empty when the source states none.
matchedEventId
String
The CLEAR Event this case describes, when CLEAR already holds it.
matchedEvent
Event
—
methodVersion
String!
Version string of the skill or handler that produced the case.
decidedById
String
Who decided it, when and why (null while `proposed`).
decidedBy
User
—
decidedAt
DateTime
—
decisionRationale
String
—
resultSignalId
String
What accepting wrote into CLEAR: the Signal, and the Event it sits on.
resultEventId
String
—
createdAt
DateTime!
—
CommentTagobject
A tag linking a user to a comment.
Field
Type
Description
user
User!
—
comment
UserComment!
—
ComputedImpactPriorobject
What has typically happened before (the Domain Ontology's ImpactPrior),
computed from CLEAR's history (V4): the Events before this one that
manifest the same hazard in the same country within the horizon, one
current figure each for one metric and population group. Computed on
read from accepted history — nothing to review. Read `numberOfCases`
beside the figure: a prior resting on three Events is not one resting on
ninety.
Only observed or reported figures count: Estimates whose method is one of
`media_report`, `government_figure`, `partner_or_cluster_figure`, `rapid_assessment`, `formal_assessment`, `registration`, `field_staff_judgement`. Figures with method `not_documented` (the
pipeline's backfilled placeholders), `model_inference`,
`exposure_model` or `prior_caseload_analogue` (itself derived from a
prior) are not history, so they are never summarised.
Field
Type
Description
hazardType
String!
GLIDE code; one of the Event's `types`.
countryLocationId
String!
The Event's country (level-0 location).
horizonYears
Int!
How far back history was taken, in years.
metric
String!
One of the Domain Ontology's seven metric types.
populationGroup
String
—
unit
String
The figures' unit (lower-cased), or null when they state none.
Figures in different units are never summarised together.
centralValue
Float!
The median of the historical figures.
lowerBound
Float!
The smallest historical figure.
upperBound
Float!
The largest historical figure.
numberOfCases
Int!
How many historical Events it rests on.
lowConfidence
Boolean!
True below three cases: a starting point, not a basis.
eventIds
[String!]!
The historical Events it rests on.
estimateIds
[String!]!
The Estimates it rests on, one per Event.
basisMethods
[EstimateMethodCount!]!
How the Estimates it rests on were arrived at, most common first, so
a reader can see what the prior is built from.
methodVersion
String!
Version of the method that computed it.
Conversationobject
One CLEAR Agent Thread, stored as the record of what the Agent told its
owner: the user's turns, the Answers, and the tools and Source documents
each Answer drew on. Readable by its owner and, read-only, by platform
admins (every admin read is logged). Written only through the CLEAR Agent's
memory adapter in clear-mvp — the owner's session plus the agent service
key — never by the owner calling the API directly; there is no delete.
Field
Type
Description
id
String!
Caller-supplied id (the Agent's thread id).
userId
String!
The owner. Every Conversation belongs to exactly one user.
title
String
—
metadata
JSON
Opaque thread metadata kept by the Agent.
createdAt
DateTime!
—
updatedAt
DateTime!
Last time the Conversation or any of its messages was written.
cursor
String!
Opaque position in "most recently active first" order. Pass the last
one of a page as `after` to get the next page.
messageCount
Int!
Number of messages in the Conversation.
messages
[ConversationMessage!]!
The most recent messages (before `before`, if given), in chronological
order — the window an Agent loads as history. Page back with `before`
for older ones.
first: Int — Max messages to return (1–500). Defaults to 500.before: String — Message id: return only messages older than this one. Pass the
oldest id from the previous window to page back through history.
ConversationMessageobject
One turn of a Conversation, as the CLEAR Agent stores it. `content` holds
the Agent's message parts (text, tool calls and results, Source documents)
and is opaque to the API.
Field
Type
Description
id
String!
Caller-supplied id (the Agent's message id).
conversationId
String!
—
role
String!
`user`, `assistant`, `system`, `tool` or `signal`.
type
String
The Agent's message format tag, returned as stored.
content
JSON!
The message parts. Text that came from outside CLEAR (documents,
signal bodies) is data, never instructions.
currentView
JSON
User turns only: what the user was looking at when they sent the turn —
the page, entity ids and active filters. Identifiers, never data.
model
String
Answers only: the model that wrote it.
inputTokens
Int
Answers only: input tokens across the whole turn, tool steps included.
outputTokens
Int
Answers only: output tokens across the whole turn.
costUsd
Float
Answers only: what the turn cost in USD, from the caller's price table.
latencyMs
Int
Answers only: time from the user's turn to the finished Answer.
createdAt
DateTime!
—
updatedAt
DateTime!
—
CreateApiKeyPayloadobject
Returned only from createApiKey. Contains the full plaintext
key that will never be retrievable again.
Field
Type
Description
apiKey
ApiKey!
—
key
String!
The full API key. Copy this immediately — it cannot be retrieved later.
CreateDevUserResultobject
Result of the admin-only `createDevUser` mutation. The plaintext API
key is returned only here — it is never stored and cannot be retrieved
later. The admin UI surfaces it once so the operator can copy-paste it
in case the welcome email bounces.
Field
Type
Description
user
User!
The newly-provisioned user.
plaintextKey
String!
The full plaintext API key (sk_live_…). Save this immediately — it
will not be retrievable from the API after this response is read.
welcomeEmailSent
Boolean!
True when the welcome email was successfully handed off to the email provider.
setPasswordTokenIssued
Boolean!
True when a long-lived set-password verification token was successfully
issued. The welcome email contains a link that consumes the token.
CreatePublicEventLinkResultobject
Returned once from `createPublicEventLink`. The token is part
of the URL and not retrievable again — same one-time-show semantics
as `createApiKey`.
Field
Type
Description
token
String!
The plaintext token. Embedded in `url` for convenience.
url
String!
Pre-built /public/event/<eventId>/<token> URL on the frontend.
Hand this straight to the share UI.
expiresAt
DateTime!
Wall-clock expiry — when the cached snapshot will be dropped
from Redis (assuming it isn't evicted earlier or revoked).
Crisisobject
A crisis aggregates multiple events into a single coherent narrative.
Field
Type
Description
id
String!
—
title
String
—
summary
String
—
enrichmentStatus
CrisisEnrichmentStatus!
Enrichment status for the pipeline drain (PENDING until enrichment runs).
scenarios
JSON
Forward-looking scenarios generated by the LLM enrichment task.
Shape: { most_likely, best_case, worst_case, description }. Null until
the enrichment task runs.
severity
Float!
Severity score (aggregated from linked events).
generalLocation
Location
General location of the crisis.
needs
JSON!
Needs associated with the crisis (JSON structure).
populationAffected
String
Population directly affected by linked events (BigInt as string).
populationInArea
String
Total population residing within the admin areas of linked events (BigInt as string).
attachments
[String!]!
Supporting documents uploaded by users (reports, photos, PDFs).
Returned as presigned URLs — the underlying storage is S3 keys, which
the resolver converts at read time so links stay short-lived.
events
[Event!]!
Events that are part of this crisis.
feedbacks
[UserFeedback!]!
User feedback on this crisis.
comments
[UserComment!]!
User comments on this crisis.
createdAt
DateTime!
When the crisis row was created.
updatedAt
DateTime!
When the crisis was last written to — bumped automatically by Prisma
on every update path (title / description / population / attachments
/ event-linkage / needs / scenarios). Useful for cache invalidation
and "recently updated" surfaces.
CurrentTotalsobject
Estimated current totals for a country bucket (ADR-0006 §4). Each metric is
`null` when there is no anchoring stock in scope to accrue flows onto.
Field
Type
Description
displacement
StockFlowEstimate
IDP displacement: latest `idp_stock` + `new_displacements` since T₀.
returns
StockFlowEstimate
Returns: latest `returnee_stock` + `new_returns` since T₀.
DailyActivityCountobject
Field
Type
Description
date
String!
YYYY-MM-DD in UTC.
total
Int!
—
counts
ActivityCountsByAction!
—
DataSourceobject
An external data source that feeds signals into the system.
Field
Type
Description
id
String!
—
name
String!
—
type
String!
Source type identifier (e.g. satellite, sensor, manual).
isActive
Boolean!
—
baseUrl
String
Base URL of the data source API.
infoUrl
String
URL with more information about this source.
synonyms
[String!]!
Alias set for source-name normalisation — variants that resolve to this
same source (e.g. "IOM DTM" / "Displacement Tracking Matrix" / "DTM").
reliability
Int
NATO Admiralty-style source-reliability grade, 1 (least) – 4 (most).
Null = ungraded; the data-quality formula treats null as 1. See clear-pipeline ADR-0004.
createdAt
DateTime!
—
updatedAt
DateTime!
—
signals
[Signal!]!
Signals collected from this data source.
DauPointobject
One day in a DAU time series.
Field
Type
Description
date
String!
ISO date (YYYY-MM-DD, UTC).
uniqueUsers
Int!
Number of distinct users who logged in on this date.
DisasterLevel1object
A level-1 category with its level-2 groups.
Field
Type
Description
name
String!
—
groups
[DisasterLevel2!]!
—
DisasterLevel2object
A level-2 group with its distinct classification codes.
Field
Type
Description
name
String!
—
codes
[String!]!
Classification codes belonging to this level-2 group (usually one).
subTypes
[DisasterType!]!
Level-3 sub-types under this level-2 group.
DisasterTypeobject
A disaster classification in a 3-level hierarchy (level1 > level2 > level3).
Events store arrays of codes (GLIDE or CLEAR IDs).
Buckets when groupBy != none. Empty when groupBy = none.
Estimateobject
A figure for one metric on an Event (the Domain Ontology's Estimate),
with its method, its uncertainty and both timestamps. Never overwritten: a
correction is a new Estimate whose `supersedes` is the one it replaces.
Where bounds are present, `lowerBound ≤ value ≤ upperBound`.
Field
Type
Description
id
String!
—
eventId
String!
—
event
Event!
—
metric
EstimateMetric!
—
populationGroup
String
IDP, refugee, returnee, host community or non-displaced affected;
null when the figure covers everyone.
value
Float!
—
unit
String
e.g. `people`, `households`.
lowerBound
Float
—
upperBound
Float
—
method
EstimateMethod!
—
attribution
EstimateAttribution!
—
validFor
DateTime!
The date the figure describes (valid time).
estimatedAt
DateTime!
When the figure was made (transaction time).
isGroundTruth
Boolean!
True for verified figures used to score earlier Estimates.
sourceSignalId
String
The Signal the figure was read from, if any.
sourceUrl
String
—
supersedesId
String
—
supersedes
Estimate
The Estimate this one corrects.
supersededBy
Estimate
The Estimate that corrects this one; null while it is current.
definitionVersion
String!
The Domain Ontology version whose definitions the figure was made
under, e.g. `0.3.0`.
createdBy
User
Who recorded it; null for system-written Estimates.
createdAt
DateTime!
—
EstimateMethodCountobject
How many of a prior's figures were arrived at by one method.
Field
Type
Description
method
EstimateMethod!
—
count
Int!
—
Eventobject
An event grouping related signals into a coherent narrative.
Field
Type
Description
id
String!
—
title
String
—
description
String
—
descriptionSignals
JSON
LLM-generated signal descriptions as JSON.
validFrom
DateTime!
—
validTo
DateTime
Event end / expiry. Null when no real end is known (not invented).
firstSignalCreatedAt
DateTime!
—
lastSignalCreatedAt
DateTime!
—
startedAt
DateTime
When the real-world event actually STARTED (its onset) — parsed from the
signal text, distinct from `validFrom`/`firstSignalCreatedAt` (record +
signal-collection times). Null when no onset could be resolved.
originLocation
Location
Origin location of the event.
destinationLocation
Location
Destination location of the event.
generalLocation
Location
General location (when no origin/destination).
representativePoint
Location
Location of the event's FIRST signal (the one recorded in
`firstSignalCreatedAt`) — a single point ready to drop as a map
marker, so a client doesn't have to fetch every signal and pick one.
The first non-null of the signal's origin → destination → general
location; null when the first signal has no located point.
Requires any authenticated content reader.
types
[String!]!
Event type tags.
severity
Int
Severity score (1–5). Aggregated from signal severities.
isDummy
Boolean!
Whether this is seed/demo data.
populationAffected
String
Estimated population affected.
populationDisplaced
String
Estimated population displaced by the event (BigInt as string).
casualties
Int
Aggregated casualties for the event (max across constituent signals).
rank
Float!
—
signals
[Signal!]!
Signals linked to this event.
alerts
[Alert!]!
Alerts created from this event.
feedbacks
[UserFeedback!]!
User feedback on this event.
comments
[UserComment!]!
User comments on this event.
escalations
[EventEscalation!]!
Escalations by users.
estimates
[Estimate!]!
Figures for this Event, newest first (by `estimatedAt`). Follows the
Event's visibility: any authenticated content reader. By default the
whole history, superseded Estimates included; `current: true` keeps
only those not yet superseded.
metric: EstimateMetriccurrent: Boolean
enrichmentTasks
[Task!]!
Enrichment Tasks about this Event, newest first. Requires any
authenticated content reader; `lastError` is redacted for all but the
requester and platform admins.
impactPriors
[ImpactPrior!]!
History: the whole ImpactPriors Workers proposed for this Event in
V1–V3, newest first. `accepted` follows the Event's visibility;
`proposed` is visible to its requester and to deciders; `rejected`
to deciders only. For what history suggests now, read
`computedImpactPriors`.
caseProposals
[CaseProposal!]!
Web cases proposed while enriching this Event (V4), newest first,
under the ImpactPrior visibility rule: `accepted` follows the Event,
`proposed` is visible to the requester and deciders, `rejected` to
deciders only.
computedImpactPriors
[ComputedImpactPrior!]!
ImpactPriors computed from CLEAR's history (V4), one per hazard the
Event manifests × metric × population group with any history, most
evidence first. Follows the Event's visibility. `horizonYears`
(default 10, at most 50) is how far back history is taken.
horizonYears: Int
EventCrisisobject
Link between a crisis and an event.
Field
Type
Description
id
String!
—
crisisId
String!
—
eventId
String!
—
collectedAt
DateTime!
—
crisis
Crisis!
—
event
Event!
—
EventEscalationobject
Tracks a user escalating an event, optionally to a crisis.
Field
Type
Description
id
String!
—
user
User!
—
event
Event!
—
isCrisis
Boolean!
Whether this has been escalated to a crisis.
validFrom
DateTime!
—
validTo
DateTime!
—
EventsPageobject
Field
Type
Description
items
[Event!]!
—
totalCount
Int!
—
hasMore
Boolean!
—
FeatureFlagobject
A feature toggle that controls runtime behavior.
Field
Type
Description
id
Int!
—
key
String!
Unique key used to look up this flag (e.g. dark_mode).
enabled
Boolean!
—
updatedAt
DateTime!
—
FindOrCreateLandmarkL4Resultobject
Outcome of findOrCreateLandmarkL4.
Field
Type
Description
locationId
String
The resolved L4 id. Null when the same-A2 safety check aborts.
reused
Boolean!
True when the call resolved to an existing L4, false when a new one
was created. Meaningless when locationId is null.
pointType
String
Provenance tag of the resolved L4 ('landmark-geocoded', 'gps', etc).
Null when the call aborted without producing a row.
abortedReason
String
Set to 'different_a2' when the candidate and source coords resolve to
different containing A2s. Null on success.
FrameEvidenceWatermarkobject
Latest-evidence watermark for a frame (ADR-0008), over the `knowledgebase`
retrieval corpus the analysis is generated from. The drain compares
`latestEvidenceAt` to the live analysis's `generatedAt` to decide whether
anything new warrants a regeneration.
Field
Type
Description
latestEvidenceAt
DateTime
Max ingestion time (`created_at`) across knowledgebase rows matching the
frame, or null when the frame has no evidence yet.
evidenceCount
Int!
Count of knowledgebase rows matching the frame.
GazetteerHitobject
A GeoNames gazetteer match for a place name. Coordinates come straight
from GeoNames — callers still validate them (e.g. the same-A2 check
against a signal's source coordinates) before trusting a fuzzy hit.
Match confidence 0–1: 1.0 for an exact normalised-name hit, else the
pg_trgm similarity of the best fuzzy match.
exact
Boolean!
True when matched exactly on the normalised name, false when fuzzy.
GroundIngestResultobject
Result of a chat-export ingest (also returned by the REST upload
route as JSON).
Field
Type
Description
created
Int!
—
skipped
Int!
—
mediaStored
Int!
—
mediaUnmatched
[String!]!
—
GroundMessageobject
A staged Signal: a canonical message parsed from a WhatsApp source,
held in the ground staging tier until its thread is reviewed. Text is
phone-number-redacted at persistence. senderName is private-tier data and
is scrubbed from anything promoted to the signals graph.
Pseudonymous per-(source, sender) reference, e.g. "s_ab12cd34ef56".
senderName
String
Raw sender display name. Private tier only — never promoted.
text
String!
Message text (redacted). Empty for caption-less media messages.
Always the reporter's original words — translations are a separate
overlay (see `translation`), never written here.
language
String
Language of `text` as a lowercased ISO 639-1 code ("ar", "en",
"fr", "es"), detected at intake without an LLM. Null when unknown
(too short, another language, or ingested before detection).
translation
GroundMessageTranslation!
On-demand translation of `text` into `locale`. `unavailable`
until requestGroundMessageTranslation queues it; poll while
`queued`.
locale: String!
mediaKeys
[String!]!
S3 keys of stored attachments.
mediaUrls
[String!]!
Presigned GET URLs for mediaKeys (1 h expiry), generated at read
time — URLs are never stored.
mediaRefs
[String!]!
Attachment filenames referenced by the export.
omittedMediaCount
Int!
Media the export omitted ("image omitted") — the message still
counts as a media message.
hasVoice
Boolean!
True when the message has a voice-note attachment (hotline
sources). Set when the row is created, so it is true even while the
voice note's media is still being stored.
transcript
String
Transcribed text of the message's voice note(s). Null until the
clear-pipeline Dagster ground_transcribe asset transcribes it, and
always null for messages without a voice note. Phone numbers are
redacted at write time.
classification
String
"field_report" | "news_digest" | "operational" | "chatter"; null
until the pipeline classification task labels the message.
uncertainty
String
Contributor's own uncertainty tag ("unconfirmed", "rumour"),
preserved from the source text.
isEdited
Boolean!
—
enrichFailedAt
DateTime
Enrichment (ground_hotline_enrich) gave up on this message: set when
the drain exhausted its attempts. While set, the message is out of the
enrichment queue — retryGroundMessage(stage: ENRICH) clears it.
enrichError
String
Last error from the enrichment drain (truncated, phone-redacted).
transcribeFailedAt
DateTime
Transcription (ground_transcribe) gave up on this voice note: set
when the drain exhausted its attempts. While set, the message is out of
both the transcription and enrichment queues ("transcription failed")
— retryGroundMessage(stage: TRANSCRIBE) clears it.
transcribeError
String
Last error from the transcription drain (truncated, phone-redacted).
threadId
String
—
createdAt
DateTime!
—
GroundMessageForClassificationobject
Pipeline-facing projection of a staged Signal for the
classification/threading worker (clear-pipeline's
classify_ground_messages task). Deliberately excludes senderName —
the pipeline never sees private-tier identity, only the pseudonymous
senderRef.
Field
Type
Description
id
ID!
—
text
String!
—
sentAt
DateTime!
—
senderRef
String!
—
hasMedia
Boolean!
True when the message carries stored media, export-referenced
attachments, or export-omitted media.
voiceMediaKeys
[String!]!
S3 keys of this message's audio attachments only (a subset of its
stored media) — empty when the message has no voice note, or while
its media is still being stored (see `hasVoice`).
hasVoice
Boolean!
True when the message has a voice attachment. Set when the row is
created, so it stays true while `voiceMediaKeys` is still empty
because the media hasn't been stored yet.
transcript
String
Transcribed text for this message's voice note(s), null until the
Dagster ground_transcribe asset transcribes them.
classification
String
Current label, null while unclassified.
threadId
String
Current thread (placeholder or pipeline-built).
enrichFailedAt
DateTime
Set once the enrichment drain has given up on the message (see
markGroundMessagesFailed).
enrichError
String
—
transcribeFailedAt
DateTime
Set once the transcription drain has given up on the voice note.
transcribeError
String
—
GroundMessageForTranslationobject
Pipeline-facing projection of a staged message for the translate
drain: text and detected language only — no sender identity.
Field
Type
Description
id
ID!
—
text
String!
Message text (phone-redacted at persistence).
language
String
Detected source language, null when unknown.
GroundMessageTranslationobject
A staged message's translation into one locale — a read-only overlay;
the original text stays canonical.
Field
Type
Description
locale
String!
Lowercased BCP-47 locale, e.g. "en".
status
GroundTranslationStatus!
—
text
String
Translated text. Null unless `status` is `ready`.
GroundSourceobject
Per-source policy record for ground intelligence (WhatsApp groups,
future hotline). Carries the consent scope, privacy default, reviewer
roles, and retention rule for everything ingested from the source. The
whole ground staging tier is private: admin/analyst only.
Transport binding — WhatsApp group JID, or hotline number.
consentScope
String
What the source's members consented to (free text, e.g. "links and
resources only"). Ingest policy is judged against this record.
consentRecordedAt
DateTime
—
consentRecordedBy
String
Who recorded/gave the consent (person name/role, not a user id).
privacyDefault
String!
Review default for derived threads. V1: always "private".
reviewerRoles
[String!]!
Global roles allowed to review threads from this source.
retentionRule
String
Free-text retention rule; enforcement is operational in V1.
isActive
Boolean!
—
createdAt
DateTime!
—
updatedAt
DateTime!
—
GroundThreadobject
A thread — a cluster of staged Signals — in the review queue. V1
threads are one-per-message placeholders until the pipeline threading
task clusters them. Lifecycle state models the correction chain; review
state is the human gate in front of the signals graph. An approved
thread is promoted and becomes a Signal.
Auth user id of the reviewer who last transitioned reviewState.
reviewedAt
DateTime
—
reviewNote
String
—
rejectReason
String
Structured rejection reason: "spam" | "not_report" | "unusable" |
"duplicate". Set only while reviewState is "rejected"; null otherwise.
promotedSignalId
String
Id of the `signals` row created when this thread was promoted
(approved_public only).
draftTitle
String
LLM-suggested headline from the hotline-enrichment job. A draft —
the ERM reviews/edits it before promotion; never used directly.
draftSeverity
Int
1-5 suggestion from the hotline-enrichment job.
draftLocationId
String
Geoparser-resolved `locations` row id, suggested by the
hotline-enrichment job.
draftDisasterType
String
Disaster-type guess from the hotline-enrichment job.
messages
[GroundMessage!]!
—
messageIds
[String!]!
Ids of the thread's messages, oldest first. The pipeline worker
selects this (via groundThreadsForSource) instead of `messages` —
it carries no message content and no sender identity.
createdAt
DateTime!
—
updatedAt
DateTime!
—
ImpactPriorobject
History: a whole ImpactPrior a Worker proposed in V1–V3, and the
decision recorded on it. Retired (2026-10-08): nothing creates or decides
one any more. The ImpactPrior is computed from history instead (see
`ComputedImpactPrior`); what analysts review is CaseProposals.
Field
Type
Description
id
String!
—
eventId
String!
—
event
Event!
—
taskId
String!
—
task
Task!
—
state
ImpactPriorState!
—
sourceKind
String!
The kind of the Task that produced it — `event.impact_prior.clear`
(CLEAR data), `event.impact_prior.web` (the web), or the pre-fan-out
`event.impact_prior` — so a client can label the source.
hazardType
String!
GLIDE code; one of the Event's `types`.
countryLocationId
String!
The level-0 (country) ancestor of the Event's primary location.
geographicScope
String!
`district` or `country`: the scope the cases were matched at.
horizonYears
Int!
How far back cases were sought, in years.
populationGroup
String
—
metric
String
—
lowerBound
Float
—
upperBound
Float
—
numberOfCases
Int!
—
basis
JSON!
The evidence: one entry per case —
`{ tier: "clear" | "web", eventId?, sourceUrl?, quote?, occurredAt?, locationLabel?, scope }`.
validFrom
DateTime
—
validTo
DateTime
—
methodVersion
String!
Version string of the skill or handler that produced it.
supersedesId
String
The previous ImpactPrior of the same `sourceKind` for the same
Event, if any. Never crosses sources.
supersedes
ImpactPrior
—
decidedById
String
Who decided it, when and why (null while `proposed`).
decidedBy
User
—
decidedAt
DateTime
—
decisionRationale
String
—
createdAt
DateTime!
—
Invitationobject
An invitation to join an organisation, with one or more team assignments.
Field
Type
Description
id
String!
—
email
String!
—
organisation
Organisation!
—
team
Team
Single team — legacy field, populated only for invitations created
before the multi-team join existed. New invitations use `teams`.
role
String!
Organisation role assigned on acceptance.
teamRole
String
Legacy single-team role. Use `teams` for new invitations.
teams
[InvitationTeam!]!
Team assignments granted to the invitee on acceptance. Empty list
means org-only access (no team).
expiresAt
DateTime!
—
acceptedAt
DateTime
—
invitedBy
User!
—
createdAt
DateTime!
—
status
InvitationStatus!
Computed from acceptedAt and expiresAt.
InvitationInfoobject
Public invitation info returned by token lookup (limited fields).
Field
Type
Description
id
String!
—
email
String!
—
organisationName
String!
—
teamName
String
Legacy single-team name (populated only for old invitations).
role
String!
—
teamRole
String
Legacy single-team role (populated only for old invitations).
teams
[InvitationInfoTeam!]!
Team assignments the invitee will be granted on acceptance.
expiresAt
DateTime!
—
status
InvitationStatus!
—
InvitationInfoTeamobject
One (team, role) assignment as returned by the public token lookup.
Field
Type
Description
teamId
String!
—
teamName
String!
—
teamRole
TeamMemberRole!
—
InvitationTeamobject
One (team, role) assignment attached to an invitation.
Field
Type
Description
team
Team!
—
teamRole
TeamMemberRole!
—
KnowledgebaseHitobject
One hit from `searchKnowledgebase`. Carries enough source
provenance (report title, url, page range) that a UI can render a
citation without a follow-up fetch, plus the parameter arrays so
the caller can highlight which filters matched.
Field
Type
Description
id
String!
—
tier
KnowledgebaseTier!
Tier this hit came from (ADR-0006). Consumers should weight/caveat
`incident` hits as lower-tier (possibly unverified) and MUST NOT let
incident figures feed the same datapoint aggregation as report figures.
reportId
String!
For a `report` hit, the ReliefWeb report id; for an `incident`
hit, `event:<event id>`.
reportTitle
String!
—
sourceUrl
String!
—
publishedAt
DateTime
Report publication date, or — for an incident — the event's onset
(`startedAt`), the recency signal used to order the incident band.
pageStart
Int!
0 for an incident hit (page range is report-only).
pageEnd
Int!
—
chunkText
String!
Report chunk excerpt, or — for an incident — the synthesised event card.
score
Float!
Merge score, larger is better. Ordering/membership only — NOT
comparable across queries or (post-ADR-0006) across tiers: it is a
positional `1/(k+rank)` from the tier-aware merge, plus a small recency
term on incidents, not the raw RRF sum.
locationIds
[String!]!
—
eventTypes
[String!]!
—
needSectors
[String!]!
—
figureS3Key
String
When this hit is a figure transcription, the cropped image's S3 key
and its kind (chart/map/table/infographic/photo) — null for text hits.
A consumer generating an infographic fetches this image and attaches it
to the LLM call; plain Q&A ignores it. Kept as a lightweight REFERENCE
(no bytes) so retrieval never pays S3 cost.
figureKind
String
—
KnowledgebaseIngestJobobject
One Dagster run kicked off by `uploadKnowledgebaseDocument`.
Returned by both the mutation (initial launch) and the polling
query. `reportId` / `reportTitle` / `s3Key` are populated from
the run's Dagster tags, which the mutation attaches at launch time —
a client that lost track of the initial payload can still recover
the identity of the document being ingested.
Field
Type
Description
runId
String!
Opaque Dagster run id. Pass to `knowledgebaseIngestJob` to
poll for completion.
status
KnowledgebaseIngestStatus!
—
reportId
String
The knowledgebase report_id the ingest is targeting. Same value
surfaces on `Knowledgebase.reportId` once the run succeeds.
reportTitle
String
—
s3Key
String
—
startedAt
DateTime
—
endedAt
DateTime
—
Locationobject
A geographic location in a hierarchy (country > state > city, etc.).
Field
Type
Description
id
String!
—
geoId
Int
GeoNames identifier.
osmId
String
OpenStreetMap identifier.
pCode
String
P-Code identifier.
name
String!
—
level
Int!
Hierarchy level: 0 = country, 1 = state/province, 2 = city, etc.
geometry
GeoJSON
Geometry as GeoJSON (Point or MultiPolygon).
parent
Location
Parent location in the hierarchy.
children
[Location!]!
Child locations one level below.
ancestorIds
[String!]!
IDs of all ancestor locations (parent, grandparent, etc.).
ancestors
[Location!]!
All ancestor locations (parent, grandparent, etc.).
population
String
Population residing within this location's geometry. Null for point locations or when not yet computed.
pointType
String
Provenance of this location's geometry. Notable values:
- 'landmark-geocoded': L4 created by the pipeline geoparser from a
landmark/place name resolved via Nominatim. The location's `name`
field is meaningful for display (e.g., 'Nyala Airport').
- 'gps' / 'source-gps' / 'centroid' / 'source-centroid': see schema
documentation on the Prisma model.
- null: legacy rows (most signal-title L4s from `createPointLocation`).
metadata
[LocationMetadata!]!
Per-type metadata (IOM DTM, INFORM, etc). Pass a type argument to filter.
By default only the current value is returned (validTo is null).
Pass current: false to include the full history.
type: Stringcurrent: Boolean
createdAt
DateTime!
When the row was first created.
updatedAt
DateTime!
Last write — useful for tracking admin polygon (re-)loads.
LocationMetadataobject
Arbitrary per-location metadata keyed by type. History is preserved:
writes close the current row (set validTo = now()) and insert a new one.
The CURRENT value for a (location, type) is the row where validTo is null.
Field
Type
Description
id
String!
—
location
Location!
—
type
String!
Free-form type string (e.g. "iom_dtm_displacement", "acaps_inform").
data
JSON!
Source-specific payload stored as JSON.
validFrom
DateTime!
When this value became current.
validTo
DateTime
When this value was superseded. Null means still current.
createdAt
DateTime!
—
updatedAt
DateTime!
—
MauPointobject
One month in a MAU time series.
Field
Type
Description
month
String!
ISO month (YYYY-MM, UTC).
uniqueUsers
Int!
Number of distinct users who logged in at least once during the
calendar month.
NominatimCacheEntryobject
A cached Nominatim-protocol geocoder response.
Field
Type
Description
id
String!
—
queryHash
String!
SHA-256 hex digest of `<endpoint>:<normalised_query>`.
query
String!
Raw query string (for debugging only).
endpoint
String!
The Nominatim endpoint that produced this response (e.g. 'search', 'reverse').
responseJson
JSON!
Raw JSON response from the geocoder.
status
String!
Lookup outcome: 'ok' / 'no_result' / 'error'.
fetchedAt
DateTime!
—
expiresAt
DateTime!
—
Notificationobject
Field
Type
Description
id
String!
—
user
User!
—
message
String!
—
notificationType
String!
—
actionUrl
String
—
actionText
String
—
status
NotificationStatus!
—
emailNotificationStatus
NotificationStatus
—
smsNotificationStatus
NotificationStatus
—
createdAt
DateTime!
—
updatedAt
DateTime!
—
Organisationobject
An organisation that owns teams and has members.
Field
Type
Description
id
String!
—
name
String!
—
slug
String!
URL-friendly identifier.
isActive
Boolean!
Whether this organisation is active. Inactive organisations are hidden from non-admin users.
createdAt
DateTime!
When this organisation was created.
updatedAt
DateTime!
When this organisation was last updated.
teams
[Team!]!
Teams belonging to this organisation.
members
[OrgMember!]!
Members of this organisation.
OrganisationUserobject
Links a user to an organisation with a role.
Field
Type
Description
id
String!
—
userId
String!
—
organisationId
String!
—
role
String!
—
OrgMemberobject
Links a user to an organisation with an org-level role.
Field
Type
Description
id
String!
—
user
User!
—
role
String!
Organisation-level role: org_admin or member.
createdAt
DateTime!
When this membership was created.
PipelineCountryobject
A country the CLEAR pipeline publishes a Situation Analysis for, with the
bounding box used to create its level-0 Country location. bbox order matches
ensureCountryLocation: [minLng, minLat, maxLng, maxLat].
Field
Type
Description
name
String!
—
iso3
String!
ISO 3166-1 alpha-3 code (e.g. "SDN"). Used by pipeline ingests that scope
external APIs by country (HAPI location_code, IOM DTM Admin0Pcode).
pcode
String!
The admin-0 location's pcode (ISO 3166-1 alpha-2, e.g. "SD"). The strong,
name-independent key for resolving the country's level-0 location — the
stored name is often the long official form, which exact-name lookup misses.
bbox
[Float!]!
—
PublicEventobject
The slim, unauthenticated view of an event used for share-link
rendering. Deliberately a new type — not a slim wrapper around
`Event` — so the field set is auditable in one place and field-
selection can't accidentally leak signals, comments, alerts, or any
other gated data through the public surface.
Returned by the `publicEvent(eventId, token)` query when the
Redis-cached snapshot for that token is still alive. Cache TTL
defaults to 30 days; entries can be evicted earlier under memory
pressure, in which case the link expires and the user has to
request a new one.
Field
Type
Description
id
String!
—
title
String
Localised event title (resolved to the canonical English text
when the snapshot was taken — the public page is not locale-aware).
description
String
Localised event description (canonical English at snapshot time).
severity
Float
Severity score (1–5) at snapshot time.
validFrom
DateTime!
Window during which the event is considered valid.
validTo
DateTime
Event end / expiry. Null when no real end is known (not invented).
types
[String!]!
Disaster type codes (e.g. `fl`, `pa`). The frontend resolves
these to display names via its own disaster-type catalogue.
primaryLocationName
String
Human-readable name of the event's primary location (general
→ origin → destination, first non-null).
primaryLocationCoords
[Float!]
`[lng, lat]` of the primary location's centroid when that
location has a Point geometry. Null for polygon-only locations —
the frontend hides the minimap in that case.
populationAffected
String
Stringified bigint (matches the authenticated `Event` field
shape). Null when unknown.
populationDisplaced
String
—
signalPoints
[PublicEventSignalPoint!]!
`[lng, lat]` for every Point location attached to the event's
constituent signals (origin / destination / general fields,
deduped by location id). Polygon-only signal locations are
omitted. Empty when no signals carry Point geometry — the
frontend hides the markers list in that case.
locationPopulation
String
Population of the event's administrative area, resolved by
walking the primary location's ancestor chain in A2 → A1 → A0
order (district → state → country) and picking the deepest non-
null. Mirrors the fallback the in-app event page uses so the
share card shows the same number. Stringified bigint; null when
no level along the chain has a population. See also
`locationPopulationLevel` and `locationPopulationName`.
locationPopulationLevel
Int
Level the population number came from: `2` (district), `1`
(state), `0` (country). Null when `locationPopulation` is
null.
locationPopulationName
String
Name of the location the population number is for (e.g. "South
Darfur"). Null when `locationPopulation` is null. Lets the
frontend label the figure with context — "Population of South
Darfur" reads more honestly than a bare number when we fell back
to a country-level figure.
locationIdp
String
Internally-displaced persons count for the event's admin area,
sourced from `locationMetadata(type = "iom_dtm_displacement")`.
Same A2 → A1 → A0 fallback as `locationPopulation`. Stringified
bigint; null when no displacement metadata exists for any level.
locationIdpLevel
Int
Level the IDP number came from. Null when `locationIdp` is null.
locationIdpName
String
Name of the location the IDP figure is for. Null when
`locationIdp` is null.
sharedAt
DateTime!
When the share link was minted.
expiresAt
DateTime!
Soft expiry — the Redis TTL the cached snapshot was written
with. The frontend uses this to render "Link expires in N days".
PublicEventSignalPointobject
One Point location attached to one of the event's signals.
Field
Type
Description
name
String
Display name of the location (e.g. "Al Fasher"). Often null
for raw point-locations like "Point 15.62, 30.21".
lng
Float!
Geographic longitude.
lat
Float!
Geographic latitude.
RefreshAggregatedDatapointsResultobject
Summary counts from a `refreshAggregatedDatapoints` run.
Field
Type
Description
computedBuckets
Int!
—
supersededBuckets
Int!
—
situationAnalysesInvalidated
Int!
Count of `situation_analyses` current rows that had their
`validTo` stamped as a cascade of the yearly-country
aggregation writes in this run. Zero means either no yearly
buckets were touched or no situation-analysis snapshot existed
yet for the affected countries.
schemaVersion
String!
—
ReportDatapointobject
One report's extracted structured datapoints. Keys inside
`data` are the six domain names: `timing_and_scope`,
`casualties`, `displacement`, `needs_and_funding`,
`access_and_incidents`, `narrative_and_confidence`. A domain
whose extraction failed is written as `null` - the operator can
re-run a targeted extraction on that domain later without touching
the successful ones.
Field
Type
Description
id
String!
—
reportId
String!
—
reportTitle
String!
—
sourceUrl
String!
—
publishedAt
DateTime!
—
reportingPeriodStart
DateTime
Window the report CONTENT describes. Not the publication date.
reportingPeriodEnd
DateTime
—
locationIds
[String!]!
Resolved `locations.id` values, deduped.
locationPcodes
[String!]!
Raw pcodes the LLM emitted that the resolver couldn't tie to a
CLEAR location. A nightly backfill re-attempts these.
Denormalised hot totals - cheap dashboard filter/sort keys.
NULL when the report doesn't headline the figure; DO NOT sum
these across rows (the JSON blob carries the incident-safe form).
totalDisplaced
Int
—
totalKilled
Int
—
data
JSON!
Exhaustive per-report payload. See the Pydantic sub-schemas in
`datapoints_schemas.py` for shape.
schemaVersion
String!
Extraction schema version, e.g. `v1`. Rows with different
versions must not be aggregated together.
extractedByModel
String!
LLM identifier that produced the extraction (e.g.
`claude-sonnet-4-6`). Used by the reviewer-audit workflow.
extractedAt
DateTime!
—
sourceId
String
The report's publisher (a `data_sources` id), resolved by the pipeline
via `resolveDataSource`. This is the report-level fallback; a figure's own
cited origin lives per-figure inside `data`. See clear-pipeline
ADR-0004.
source
DataSource
The resolved publisher, e.g. "IOM DTM" or "WFP". Exposed alongside
`sourceId` so a client can label a report without a second round trip.
**Null for rows extracted before source attribution landed (schema v1).**
Those were never re-extracted, so clients must keep a fallback - deriving a
publisher from the `sourceUrl` host yields the aggregator ("reliefweb.int"),
not the publisher, so it is a label of last resort.
ReportFigureobject
Field
Type
Description
id
String!
—
reportId
String!
—
reportTitle
String!
—
sourceUrl
String!
—
pageNumber
Int!
1-indexed source page.
bbox
[Float!]!
Source-page bounding box [x0, top, x1, bottom] in PDF points; empty on full-page fallback.
isFullPage
Boolean!
—
s3Key
String!
S3 key of the cropped image.
kind
String!
chart | map | table | infographic | photo (logos are dropped, not stored).
title
String
—
description
String
—
transcription
JSON
Structured transcription (rows / nested groups / callouts) from the vision pass.
sourceId
String
Publishing source (data_sources id) for attribution.
locationIds
[String!]!
—
locationPcodes
[String!]!
—
eventTypes
[String!]!
—
needSectors
[String!]!
—
timeRangeStart
DateTime
—
timeRangeEnd
DateTime
—
extractedByModel
String!
—
extractedAt
DateTime!
—
RotateDevUserApiKeyResultobject
Result of the admin-only `rotateDevUserApiKey` mutation.
Field
Type
Description
user
User!
The user whose key was rotated.
plaintextKey
String!
The fresh plaintext API key — same one-time-delivery rules as createDevUser.
notificationEmailSent
Boolean!
True when the rotation-notice email was successfully handed off.
Signalobject
A source observation ingested from a data source or filed manually.
Upstream source payloads are stored internally and are not returned on this type.
Field
Type
Description
id
String!
—
source
DataSource!
The data source this signal was collected from.
status
SignalStatus!
Processing status for the pipeline drain (NEW until downstream runs).
processedAt
DateTime
When the downstream pipeline finished processing this signal (null while NEW).
contentHash
String
Fingerprint of the source's raw data, for sources whose records get
revised in place (e.g. IDMC). Null for sources that never revise a signal
after creation.
lastRevisedAt
DateTime
When the API last applied an in-place content revision to this signal
(e.g. an IDMC IDU row revised upstream). Null if never revised.
rawS3Key
String
Pointer to the raw payload blob in the S3 data lake, when landed there.
externalId
String
Stable upstream identifier (e.g. "dataminr:{alertId}"). Used to
deduplicate ingestion — (source, externalId) is unique.
publishedAt
DateTime!
—
collectedAt
DateTime!
—
url
String
—
title
String
—
description
String
—
severity
Int
Severity score (1–5). From data source or estimated by pipeline.
casualties
Int
Reported casualties for the signal. Sourced from ACLED's fatalities
field; for Dataminr, parsed from raw text via regex.
media
[String!]!
Media URLs (S3 keys for manual uploads, or source URLs for pipeline signals).
isDummy
Boolean!
Whether this is seed/demo data.
originLocation
Location
Origin location of the signal.
destinationLocation
Location
Destination location of the signal.
generalLocation
Location
General location (when no origin/destination).
events
[Event!]!
Events this signal is linked to.
feedbacks
[UserFeedback!]!
User feedback on this signal.
comments
[UserComment!]!
User comments on this signal.
locationChallenge
SignalLocationChallenge
Open Location challenge for this signal, if any (null when none).
SignalLocationChallengeobject
An analyst's Location challenge on a Signal, with an optional Location
correction (Location trust v1). Queue only — status is always "consideration",
there is no accept/reject, and it never mutates the Signal's own geometry.
Field
Type
Description
id
ID!
—
signalId
String!
—
status
String!
v1 is always "consideration".
note
String
Optional note explaining why the pin looks wrong.
proposedLng
Float
Proposed corrected point. Both lng and lat are set together, or both null
(a bare challenge with no correction).
proposedLat
Float
—
proposedName
String
Optional label for the proposed point.
createdBy
String!
Auth user id of whoever filed the challenge.
createdAt
DateTime!
—
updatedAt
DateTime!
—
hasProposedPoint
Boolean!
True when proposedLng/proposedLat are both set.
SignalsPageobject
Field
Type
Description
items
[Signal!]!
—
totalCount
Int!
—
hasMore
Boolean!
—
SituationAnalysisobject
One (country × year) situation-analysis snapshot. Cache read
path — always current unless `asOf` is supplied for historical
reads.
Field
Type
Description
id
String!
—
countryLocationId
String!
FK to `locations.id` — the country (A0) this analysis covers.
windowStart
DateTime!
—
windowEnd
DateTime!
—
windowKind
String!
Granularity of the analysis window — `yearly` today. Part of the
bucket key alongside `countryLocationId` and `windowStart`;
`windowEnd` is a derived detail and is never matched on.
data
JSON!
Full analysis blob. Top-level keys: `datapoints`,
`ai_summary`, `context_risks`, `hazards_and_vulnerabilities`,
`displacement`, `sectors`, `sources`. LLM-generated
components carry their own `source_report_ids` for
per-component provenance.
sourceReportIds
[String!]!
Denormalised union of every contributing report id across all
components. Same identity as the `report_id` on the underlying
`knowledgebase` / `report_datapoints` rows.
aggregatedDatapointId
String
Aggregated-datapoints snapshot this analysis was generated
against, when known. Null for early bootstrap runs.
generatedByModel
String!
LLM identifier (e.g. `claude-sonnet-4-6`).
Deterministic-only Phase B runs record `deterministic:<version>`.
generationCostUsd
Float
Total LLM cost across all component calls. Null when the
generator didn't track cost or the run was deterministic-only.
generatedAt
DateTime!
—
validFrom
DateTime!
Bitemporal validity — this snapshot's lifetime as a "current"
row. `validTo` is null when the row is still the current one
for its bucket; else it carries the timestamp when a newer
regeneration superseded it.
validTo
DateTime
—
schemaVersion
String!
Bumped when the output taxonomy OR the prompt set changes.
Different-version rows never mix on trend views.
StatsBucketobject
Field
Type
Description
key
String!
Bucket label — depends on groupBy: glide code, severity number as
string, or ISO date/week/month.
count
Int!
—
StockFlowEstimateobject
One metric's estimated current total (ADR-0006 §4): the latest
authoritative stock plus the flows reported after its reference date T₀.
Flows at or before T₀ are already embedded in the stock and are not added
again - the invariant that stops returnee/IDP totals from over-counting.
Field
Type
Description
total
Float!
`stock` + `flowsSince` - the headline estimated current total.
stock
Float!
The anchoring latest authoritative stock value (API-reconciled).
flowsSince
Float!
Deduped sum of the flows whose as-of date is strictly after T₀.
t0
DateTime!
T₀ - the anchor stock's reference date. Flows at/before it are treated
as already counted inside `stock`.
flowCount
Int!
Reports contributing forward flows - a provenance count, not a count of
distinct flow events.
SyncEventCardsResultobject
Result of `syncEventCards` — how many event cards were written vs
skipped (an id that no longer resolves to an event).
Field
Type
Description
synced
Int!
—
skipped
Int!
—
Taskobject
One unit of Worker-performed work (ADR-0010).
Field
Type
Description
id
String!
—
kind
String!
The kind of work, e.g. `event.impact_prior.web` (the web search
that proposes signals; the name is historical). A Worker claims by exact
kind. One request fans out into one Task per enabled source kind. Older
Tasks may carry the retired whole-prior kinds `event.impact_prior`
and `event.impact_prior.clear`.
subjectType
String!
The subject's type, e.g. `event`.
subjectId
String!
The subject's id, e.g. an Event id.
payload
JSON!
Per-kind inputs, e.g. `{ "horizonYears": 10 }`.
status
TaskStatus!
—
origin
TaskOrigin!
—
requestId
String!
Shared by every Task one request fanned out into (one per source
kind). The per-requester daily cap counts distinct requests, not
Tasks.
requesterId
String
The user who requested it; null for origin `rule`.
requester
User
—
teamId
String
The view-scope team passed at request time (an authorisation hint,
not an Event team — Events have none).
leaseOwnerId
String
The Worker (a service user) or person currently holding the lease.
leaseOwner
User
—
leaseExpiresAt
DateTime
When the current lease lapses. A heartbeat extends it by
TASK_LEASE_MINUTES; past this instant the Task is claimable again.
leaseToken
String
Secret minted per claim. Returned only to the lease owner (null for
everyone else); the Worker presents it on heartbeat, complete and fail.
A new claim mints a new token, so a run whose lease lapsed and was
reclaimed — even by the same Worker identity — can no longer write.
attempts
Int!
Times the Task has been claimed.
maxAttempts
Int!
Claims allowed before the Task is marked FAILED.
lastError
String
The last Worker-reported error. Visible to the requester and platform
admins only; null for everyone else.
cancelRequestedAt
DateTime
Set when a LEASED Task was cancelled; the Worker learns at its next
heartbeat or completion and stops.
cancelledById
String
—
outcome
String
Kind-specific result vocabulary. For `event.impact_prior.*`:
`produced` or `no_prior_found`; for the web kind also
`no_new_cases` (every case found was already proposed for the Event).
result
JSON
Raw Worker output, kept for audit. The typed result lives beside the
subject (see `Event.caseProposals`).
model
String
Spend as the Worker reported it on completion.
inputTokens
Int
—
outputTokens
Int
—
costUsd
Float
—
completedAt
DateTime
—
createdAt
DateTime!
—
updatedAt
DateTime!
—
Teamobject
A team within an organisation, scoped to specific locations.
Field
Type
Description
id
String!
—
name
String!
—
slug
String!
URL-friendly identifier, unique within the organisation.
description
String
—
organisation
Organisation!
The organisation this team belongs to.
members
[TeamMember!]!
Members of this team.
locations
[Location!]!
Locations this team is scoped to. Empty means global monitoring.
createdAt
DateTime!
—
updatedAt
DateTime!
—
TeamMemberobject
Links a user to a team with a team-level role.
Field
Type
Description
id
String!
—
user
User!
—
role
String!
Team-level role: lead, analyst, or viewer.
createdAt
DateTime!
—
TranslationCoverageobject
Per-(entity_type, locale) coverage snapshot used by the admin
dashboard to see how much of the catalog has been translated.
- canonicalCount: total entities of this type that *could* be
translated (i.e. exist in the canonical table).
- translatedCount: number with a row in the translations sidecar
for this locale.
The fraction translatedCount / canonicalCount is the live coverage
for that (type, locale) cell — anything < 1.0 means the next read of
one of the missing entities by a user on that locale will fall back
to canonical English (and trigger the lazy-on-read enqueue, see
utils/translation-loader.ts).
Field
Type
Description
entityType
String!
—
locale
String!
—
canonicalCount
Int!
—
translatedCount
Int!
—
TranslationQueueItemobject
A pending (re)translation request — the durable replacement for the
lazy-on-read Celery enqueue. Drained by the Dagster translation consumer,
which translates the entity at `locale` and writes it back via
upsertTranslations (which clears the queue row).
A single translation row, returned by the admin/pipeline-only
translations(entityType, entityId) query so the pipeline can compare
stored source-hashes against the canonical row and decide which fields
(if any) need re-translating.
Field
Type
Description
locale
String!
—
data
JSON!
Translated payload, same shape as the canonical entity per type.
sourceHashes
JSON
Per-field SHA-256 hashes of the canonical English source that was
used to produce `data`. Null on rows written before hashes were
introduced — treat null as "all fields stale".
createdAt
DateTime!
—
updatedAt
DateTime!
—
UpsertAnalysisResultobject
Summary of an `upsertAnalysis` mutation — whether it superseded a previous
row, or was skipped by the 24h regeneration floor (ADR-0008).
Field
Type
Description
analysisId
String!
The current analysis row for the frame after the call — the newly-created
row, or (on a skip) the existing current row.
supersededPrevious
Boolean!
`true` when the mutation stamped `validTo` on a previous current row
for the same frame, `false` when this was the first row or a skip.
skipped
Boolean!
`true` when the 24h floor made this a no-op (only `lastSyncedAt` was
bumped, no new version written). `false` on an actual (re)generation.
reason
String
Why the write was skipped (e.g. `within-24h-floor`), else null.
UpsertKnowledgebaseResultobject
Result of a knowledgebase upsert — summary counts for logging.
Field
Type
Description
reportId
String!
—
chunksDeleted
Int!
—
chunksInserted
Int!
—
UpsertReportDatapointsResultobject
Result of `upsertReportDatapoints` - summary for logs.
Field
Type
Description
reportId
String!
—
schemaVersion
String!
—
createdOrReplaced
Boolean!
`true` when the mutation replaced a previously extracted row,
`false` when it created the first row for the report.
UpsertReportFiguresResultobject
Field
Type
Description
reportId
String!
—
count
Int!
Number of figures written.
UpsertSituationAnalysisResultobject
Summary of an `upsertSituationAnalysis` mutation — reports
whether the write superseded a previously-current row.
Field
Type
Description
situationAnalysisId
String!
—
countryLocationId
String!
—
supersededPrevious
Boolean!
`true` when the mutation stamped `validTo` on a previous
current row for the same bucket, `false` when this was the
first row for the (country, window) tuple.
UpsertTranslationsResultobject
Result of upserting one or more locale rows for a given entity. Carries
the locales that were written so the caller (typically clear-pipeline)
can confirm coverage without a follow-up read.
Field
Type
Description
entityType
String!
—
entityId
String!
—
locales
[String!]!
—
Userobject
A registered user with role-based access.
PII fields (`email`, `phoneNumber`, `role`, `isActive`) and the
private relation set (`alerts`, `notifications`, `organisations`,
`teamMemberships`, `feedbacks`, `comments`, `escalations`) are
gated server-side:
- PII: returned when caller IS the user, is a global admin, OR
shares at least one organisation with the user. Otherwise null
(PII) or empty array (private relations).
- Private relations: returned only when caller IS the user OR is
a global admin. Sharing an organisation does NOT grant access
to another member's inbox / comment history.
Schema makes these fields nullable so the gate can return null when
the caller is not authorised, instead of throwing — a logged-in
analyst browsing an event's comments shouldn't see a hard error on
the commenter's email.
Field
Type
Description
id
String!
—
email
String
—
name
String!
—
emailVerified
Boolean!
—
phoneNumber
String
—
image
String
—
role
String
User role: viewer, analyst, admin, or pending. Null when caller is not
authorised to see this user's role.
isActive
Boolean
Null when caller is not authorised to see this field.
language
String!
Preferred UI language code (BCP-47 / ISO 639-1, e.g. "en", "ar"). Defaults to "en".
enableInAppNotification
Boolean!
—
enableEmailNotification
Boolean!
—
enableSMSNotification
Boolean!
—
createdAt
DateTime!
—
updatedAt
DateTime!
—
alerts
[UserAlert!]!
Alerts received by this user. Empty for non-self / non-admin
callers.
notifications
[Notification!]!
Empty for non-self / non-admin callers.
defaultTeam
Team
The user's default team (last selected). Null for non-self /
non-admin callers.
organisations
[OrganisationUser!]!
Empty for non-self / non-admin callers.
teamMemberships
[TeamMember!]!
Empty for non-self / non-admin callers.
feedbacks
[UserFeedback!]!
Empty for non-self / non-admin callers.
comments
[UserComment!]!
Empty for non-self / non-admin callers.
escalations
[EventEscalation!]!
Empty for non-self / non-admin callers.
UserActivitySummaryobject
Field
Type
Description
user
User!
—
total
Int!
—
counts
ActivityCountsByAction!
—
UserAlertobject
Tracks an alert delivered to a user — view status.
Field
Type
Description
id
String!
—
user
User!
—
alert
Alert!
—
viewedAt
DateTime
When the user viewed this alert.
UserCommentobject
A user comment on a signal, event, or crisis, with reply support.
Field
Type
Description
id
String!
—
user
User!
—
event
Event
—
signal
Signal
—
crisis
Crisis
—
comment
String!
—
isCommentReply
Boolean!
Whether this comment is a reply to another comment.
repliedToCommentId
String
ID of the comment being replied to, if any.
tags
[CommentTag!]!
Users tagged in this comment.
createdAt
DateTime!
—
updatedAt
DateTime!
—
UserEngagementMetricsobject
Point-in-time engagement summary derived from auth.login activity.
All three windows are trailing from `asOf` (inclusive).
Field
Type
Description
asOf
DateTime!
Reference moment the windows are anchored to. Defaults to NOW()
when the caller doesn't specify it.
dau
Int!
Unique users with at least one login in the trailing 24 hours.
wau
Int!
Unique users with at least one login in the trailing 7 days.
mau
Int!
Unique users with at least one login in the trailing 30 days.
dauMauRatio
Float!
Stickiness ratio (DAU / MAU) as a percentage. Industry benchmark:
≥20% indicates a frequently-returning user base. Returns 0 when MAU
is 0 so the field is safe to chart without null-handling.
UserFeedbackobject
User feedback on a signal, event, or crisis — rating and optional text.
Field
Type
Description
id
String!
—
user
User!
—
event
Event
—
signal
Signal
—
crisis
Crisis
—
rating
Int!
Rating from 1 to 5.
text
String
Optional textual feedback.
createdAt
DateTime!
—
updatedAt
DateTime!
—
WebhookDeliveryobject
A single delivery attempt-sequence to one subscription for one
incoming event. attemptNumber advances in place across retries.
Field
Type
Description
id
String!
—
subscriptionId
String!
—
eventId
String!
GlitchTip's event/issue ID. Useful for correlating a delivery
back to the source issue in GlitchTip.
eventType
String!
Event type extracted from the source payload (e.g. issue.new).
attemptNumber
Int!
1-indexed. 1 = first attempt; up to 5 for retries.
responseStatus
Int
Last response HTTP status code, if the target responded.
responseBody
String
Truncated response body (max 8 KiB).
error
String
Network or transport error message, if the request never got a response.
succeededAt
DateTime
Non-null once a 2xx was received. Terminal state.
nextRetryAt
DateTime
Scheduled time of the next retry. Null when there is no next attempt
(either succeeded, or exhausted 5 attempts = dead-lettered).
createdAt
DateTime!
—
status
WebhookDeliveryStatus!
One of: pending, succeeded, retrying, dead. Derived from the fields
above so the admin UI doesn't need to reimplement the logic.
WebhookSubscriptionobject
Outbound webhook subscription. Every incoming GlitchTip alert is
fanned out to every active subscription whose event-type filter
matches. Managed by platform admins.
Field
Type
Description
id
String!
—
name
String!
Human-readable label shown in the admin UI. Not sent downstream.
targetUrl
String!
Target URL that receives HMAC-signed POST requests.
secret
String
HMAC-SHA256 shared secret used to sign outbound requests.
Only returned on create + rotate; null on all other reads to keep
the secret out of admin browser DevTools tabs. Rotate via
rotateWebhookSubscriptionSecret.
active
Boolean!
Paused subscriptions are skipped during fan-out. Deliveries do
NOT resume automatically when re-enabled — only new events fan out.
eventTypeFilter
[String!]!
Event-type allowlist. Empty = fire on all events.
Values match GlitchTip's 'alias' field (e.g. issue.new, issue.regression, issue.resolved).
createdBy
String
User ID that created this subscription. Kept for audit.
createdAt
DateTime!
—
updatedAt
DateTime!
—
recentDeliveries
[WebhookDelivery!]!
Most-recent delivery attempts for this subscription. Ordered newest first.
Capped at 50 in the resolver to keep the admin UI fast.