Skip to Content

Reference

Marine Evidence API

Eyesea tracks candidate marine pollution observed by satellite as cases, records the evidence gathered on each, and publishes an assessment of what that evidence supports. Reports made in the field, and the labels drawn from both, are licensed separately. Version 1.2.1.

Overview

A case is not a record of a detection. It is a record of an investigation into one candidate feature, opened when a detector identifies that feature in a satellite scene and maintained thereafter. Evidence is retrieved and recorded against the case over the hours and days that follow, and the assessment is derived afresh from whatever evidence exists at the time of each request. A case may therefore move from unresolved to a firmer status days after it was opened, and a conclusion drawn from it is valid only against the evidence then available.

The following hold for every case:

  • Supporting and contradicting evidence both remain visible.
  • Alternative and untested hypotheses remain explicit.
  • Evidence that is absent, pending, failed or withheld is represented rather than omitted.
  • Conclusions are constrained by the evidence available at the time of the request.
  • Every entry references the record it derives from, and provenance is retained on each evidence record.
  • Changes of assessment can be reconstructed from the recorded history.

Terms

These terms carry distinct meanings throughout this reference and are not interchangeable.

detection
A candidate feature identified in a single satellite scene by a detector model.
case
The record opened from a detection and maintained thereafter. A case accumulates evidence and is reassessed as that evidence arrives.
evidence
An observation or reading recorded against a case, with its source, quality grade and retrieval time.
hypothesis
A candidate physical explanation for the observed feature. Hypotheses describe what a feature is, not what produced it.
assessment
A derived summary of what the evidence on a case supports, contradicts and leaves open.
confidence
A categorical value derived from the amount of independent support for the leading hypothesis.
decision
The output of a deterministic rule set, recorded as a status transition together with the facts it read.
verdict
An adjudication recorded by a human reviewer.
attribution
Identification of the source of a feature, as distinct from its nature. Available only under attribution:read.

Case lifecycle

Case 59f8d98a-296b-4c08-9a0e-5b73676e1e3c, opened 6 September 2026. The values below are those held in the ledger, and the case can be retrieved with aledger:read key.

Detection05:44 UTC, case opened 16:23

A Sentinel-1 acquisition over the Norwegian Sea (71.306 N, 16.450 E, 1,021 m water depth, 151 km from shore) yields a 177,791 m² dark feature. detector_score 0.986, p_oil_corpus 0.93. The case opens with status NEW. The detector output is retained for traceability and does not contribute to hypothesis scoring.

Sentinel-1 radar chip: a dark, narrow feature running down the centre, outlined in orange, against mottled grey backscatter. A one kilometre scale bar and the calibrated and raw scores, the area and the acquisition time run along the lower edge. The chip is headed: screening indication, not confirmation of oil.
The preview returned by GET /v1/cases/{case_id}/preview for this case. The orange outline marks the detected feature. The chip is 448 by 448 and carries a scale bar, the calibrated and raw scores, the area and the acquisition time.

Context16:31 UTC

Wind, sea state, seabed and recurrence evidence is retrieved. One explanation is weakened and none is established, and the status becomes UNRESOLVED. At 20:00 the look-alike rule set evaluates the case; no flag fires and the status is unchanged.

  • neutralMETEOROLOGICALModel wind of 4.3 m/s at acquisition falls inside the 2.5 to 15 m/s observability band, but the six-hour minimum was 1.8 m/s. A scene-wide calm does not account for the feature, and local calm patches are not excluded.
  • neutralOCEANOGRAPHICWater depth of 1,021 m and no reef within 5,000 km. No seabed or reef signature is indicated; fronts and internal waves are not excluded by depth.
  • neutralOIL_FILMOne prior detection within 5 km, 2.8 km distant, with no footprint overlap. This indicates recurrence in the area rather than a fixed feature, against a ledger that begins on 19 August 2026.

Corroboration and review20:30 to 21:31 UTC

An independent detection and two independent readings are recorded.

  • supportsOIL_FILMAn independent provider recorded seven slicks within 15 km and 36 h; the nearest is 4.6 km distant, 13.3 h apart, and 2.2 km² in area. This corroborates slick-like activity in the same water, not this outline.
  • supportsOIL_FILMTwo independent reviews each rank an oil-film mechanism first of four. The later review records three conflicts between image and data and identifies eight discriminators.

Assessment

"assessment": {
  "assessment_version": "assessment-rules-0.1",
  "current_status": "UNRESOLVED",
  "confidence": "high",
  "confidence_basis": "2 supporting inputs beyond the detector, 1 of them observations, nothing contradicting",
  "contested": false,
  "primary_hypothesis": { "hypothesis": "OIL_FILM", "score": 2, "support": 2, "contradiction": 0, "review_rank": 1 },
  "alternative_hypotheses": [ { "hypothesis": "METEOROLOGICAL", "score": 0 }, { "hypothesis": "OCEANOGRAPHIC", "score": 0 } ],
  "untested_hypotheses": [ "ARTIFACT", "BIOGENIC_FILM", "SHIP_WAKE" ],
  "missing_evidence": [
    { "evidence": "OPTICAL_COVERAGE", "status": "pending", "would_discriminate": ["BIOGENIC_FILM", "OIL_FILM"] },
    { "evidence": "ATTRIBUTION", "status": "withheld", "would_discriminate": ["VESSEL_SOURCE"] },
    { "evidence": "HUMAN_VERDICT", "status": "absent" } ],
  "contradictions": [ { "kind": "data_conflict", "detail": "the reviewer flagged 3 contradiction(s) between image and data" } ],
  "conclusion": "OIL_FILM (mineral oil film, source unspecified) is the best-supported explanation at high confidence: supported by cross detection, independent review; nothing on file contradicts it. Not excluded: METEOROLOGICAL, OCEANOGRAPHIC. Case status UNRESOLVED. Not a measurement and not confirmation of oil."
}

Two inputs beyond the detector support OIL_FILM and none contradicts it, giving a confidence of high. The alternative hypotheses are outscored rather than excluded, and three remain untested. The conflicts recorded by the reviewer appear under contradictions although they do not alter the ranking.

32d6fcc1Contradicting evidence and an adjudicated outcome

A case in the northern North Sea on 22 August 2026 followed the same sequence with a different result. Wind of 7 m/s fell inside the observability band and above the threshold at which natural films persist, so the WIND evidence contradicted bothMETEOROLOGICAL and BIOGENIC_FILM rather than remaining neutral to them. No independent detection fell within the window. A review ranked an oil mechanism first and recorded six conflicts between image and data. Twelve hours after acquisition a human reviewer recorded a verdict of CONFIRMED_OIL.

confidence then reads confirmed, the conclusion states the verdict, and history carries the transition from UNRESOLVED toCONFIRMED_OIL with the verdict as its reference. Records preceding the verdict are retained unchanged.

The assessment

Each case carries an assessment, derived from the evidence on record at the time of the request under the rule set named in assessment_version. Derivation is a read operation: no records are written, no model is invoked, and no information is introduced beyond what the ledger holds. Each entry references the record from which it derives. Two requests against identical evidence under the same rule set return identical assessments.

primary_hypothesis identifies the best-supported explanation on record. It is not a verdict. alternative_hypotheses carries the remaining hypotheses with their scores, untested_hypotheses those on which no evidence bears, andmissing_evidence those evidence types not present, each with its status and the hypotheses it would discriminate between.

  • current_statuscases:readThe case status from which the assessment was derived.
  • confidencecases:readOne of none, low, moderate, high or confirmed.
  • primary_hypothesiscases:readThe leading explanation, with its score, support and contradiction counts, independent observation count, review rank and rule flags. Null where the case is not assessable.
  • conclusioncases:readA single sentence stating the leading hypothesis, the evidence for and against it, the hypotheses not excluded, the case status and the applicable disclaimer.
  • confidence_basis, contestedledger:readThe counts from which the confidence was derived. contested is set where two hypotheses tie, or where the rule set, the weighed evidence and the reviews do not agree.
  • alternative_hypotheses, untested_hypothesesledger:readHypotheses addressed by the evidence or by a review, ranked; and those on which no evidence bears.
  • supporting_evidence, contradicting_evidence, neutral_evidenceledger:readRelevance entries carrying ref, hypothesis, effect, reason and source_class. Each reason cites the fields and thresholds applied.
  • missing_evidenceledger:readEvidence not present, each with a status of absent, pending, failed or withheld, and the hypotheses it would discriminate between.
  • contradictionsledger:readMaterial contradictions: evidence against the leading hypothesis, disagreement between the rule set and the weighed evidence, a second review that does not concur, or conflicts between image and data recorded by a reviewer.
  • limitationsledger:readStatements the assessment does not support, with the reason in each case.
  • historyledger:readOne dated entry per recorded event, oldest first. Entries that change the status carry from_status, to_status and changed.
  • based_onledger:readInput counts and the most recent input timestamp, permitting two assessments to be compared.
  • attributionattribution:readVessel-source evidence and counts, rule flags, and review hypotheses at mechanism level with the evidence for and against each.

source_class identifies the kind of input an entry represents. A hypothesis score is the count of its supporting entries less the count of its contradicting entries. Detector outputs are retained for traceability but do not contribute to hypothesis scoring.

detector
Output of the detector model on the case.
observation
A measurement, or a detection recorded independently by another provider.
interpretation
A reading of the same data by an independent reviewer.
adjudication
A verdict recorded by a human reviewer.

The score is an unweighted count. Entries are not scaled by quality grade, by the mutual independence of their sources, or by the strength with which they bear on the hypothesis. Quality determines which record is evaluated rather than how heavily it counts: the most recent record of each evidence type is used, with a grade of B or better preferred for cross-detection and optical coverage. Each record carries its own grade from A to D, so a consumer requiring weighted evidence can apply its own scheme to the same records.

Because the assessment is derived rather than stored, any change-feed entry for a case indicates that its assessment may differ from the one previously retrieved. Retrieve the case again, compare confidence, primary_hypothesis andcontradictions, and consult history for the event responsible. A human verdict closes a case and sets confidence to confirmed; evidence recorded before the verdict is retained unchanged.

Confidence

confidence is a categorical value derived from the evidence. It is neither a score nor a probability. Only inputs beyond the detector contribute to it.

  • confirmedA human verdict is recorded.
  • highTwo or more supporting inputs beyond the detector, at least one of them an observation, with nothing contradicting.
  • moderateAt least one independent observation supports the leading hypothesis, and support exceeds contradiction.
  • lowThe case is contested; or no input beyond the detector supports the leading hypothesis; or it is contradicted as often as it is supported; or it is supported only by an interpretation.
  • noneNot assessable: context is not yet recorded, no wind value falls within two hours of acquisition, or wind lies outside the 2.5 to 15 m/s radar observability band. primary_hypothesis is null and the conclusion states the reason.

Confidence counts inputs without grading them. Two C-grade observations satisfyhigh on the same terms as two A-grade observations, and no level distinguishes a strong independent detection from a weak one. The quality grade is present on each evidence record and confidence_basis reports the counts, so a stricter threshold can be applied downstream from the same data.

contested is set wherever the rule set, the weighed evidence and the reviews do not agree, and the disagreement is itself recorded under contradictions. A case identified by the rule set as a likely look-alike and also detected by an independent provider is contested; it is not resolved in either direction.

Hypotheses

Hypotheses describe the physical nature of an observed feature. They stop short of source attribution: the nature of a feature is addressed under ledger:read, while the vessel or installation responsible for it is a separate matter addressed only under attribution:read.

s1Radar oil cases

  • OIL_FILMMineral oil film, source unspecified. This is the hypothesis asserted by the detector.
  • BIOGENIC_FILMNatural surfactant film or bloom.
  • METEOROLOGICALLow wind, wind shadow or rain cell.
  • OCEANOGRAPHICCurrent front, internal wave or shallow-water signature.
  • SHIP_WAKEVessel wake or turbulence.
  • ARTIFACTProcessing or scene-edge artefact.

s2Optical material cases

  • FLOATING_MATERIALDrifting material of the detected class. This is the hypothesis asserted by the detector.
  • BENTHIC_OR_INTERTIDALSeabed vegetation or intertidal signature.
  • CLOUD_OR_HAZECloud shadow or haze.
  • FOAM_OR_WHITECAPFoam or whitecaps.
  • FIXED_FEATUREA fixed feature: shoal, structure or moored object.
  • VESSEL_OR_WAKEA vessel or wake within the scene.

Independent reviews rank mechanisms drawn from a fixed and more specific vocabulary. Under ledger:read each mechanism maps to the hypothesis above it, so a review contributes its ranking without its source-level reasoning; underattribution:read the mechanisms are returned directly. That mapping, together with every reason code, confidence level, effect, status and evidence type used in responses, is published at /v1/vocabulary.

Radar and optical

Each case carries a stack identifying the sensor it originates from. Both share a single response shape. The stack parameter on the cases endpoint filters between them, and the change feed carries both.

s1Sentinel-1 radar oil
Scored by detector_score and p_oil_corpus, evaluated under the look-alike rule set, and adjudicated as CONFIRMED_OIL orCONFIRMED_NON_OIL.
s2Sentinel-2 optical material
Carries a material_class of macroalgae, floating debris or organic material, and a material_score in place of the oil scores. Evaluated under a separate material rule set, carries the optical disclaimer, and is adjudicated as CONFIRMED_MATERIAL or CONFIRMED_NON_MATERIAL.

Optical cases accumulate the same context evidence: wind, sea state, static context, recurrence and optical coverage. Cross-detection against another provider, AIS evidence and the independent review track apply to radar cases only. Where a review is therefore absent, the assessment records it under missing_evidence.

Authentication

The API is read-only. Every request carries a bearer key, issued per organisation.GET /v1/me returns the scopes a key holds, together with its plan, rate limit and monthly quota.

Scopes fall into three families, licensed separately. Within a family each scope includes the one before it; between families nothing is implied, so a key holding case scopes does not reach field reports or training labels.

Casescases:read < ledger:read < attribution:read
Satellite screening cases and the evidence recorded against them.
Field reportsreports:read < reports:annotations
Reports of pollution observed in person, with photographs and an item inventory.
Training labelslabels:read
Verified labels with the provenance of each, for training and evaluation.

A key cannot obtain material above its scopes through any endpoint, parameter or derived field. Where such material exists on a case, it is reported undermissing_evidence with a status of withheld.

Authorization: Bearer eysk_live_...
cases:readCase snapshot
The case record: status, model scores, the most recent wind, sea state and static context, recurrence, cross-detection and optical coverage, any recorded verdict, the rule flags that fired, and the preview image. The assessment headline: current status, confidence, primary hypothesis and conclusion. Position is rounded to approximately 100 m.
ledger:readEvidence ledger
The evidence record in full, and the complete assessment. Each evidence record with its source, quality grade, retrieval time and relevance to each hypothesis; decisions as status transitions; independent reviews as ranked hypothesis families with conflict and discriminator counts; alternative and untested hypotheses, missing evidence, contradictions, limitations and history. Also the change feed, the expand parameter, the detection outline and the full-precision position.
attribution:readSource attribution
Material bearing on the source of a feature: AIS evidence, bright-target and ship-to-ship features, vessel decision flags, review mechanisms at source level, and the attribution block of the assessment. Granted per partner under a written agreement and recorded against the key.
reports:readField reports
Reports of pollution observed in person: the item inventory, scene, impact, estimated weight, photographs and place. Position is rounded to approximately 100 m.
reports:annotationsReport annotations
Adds the per-object image annotations and the model analysis to each report, and serves the position at full precision.
labels:readTraining labels
Verified labels with the provenance of each: the channel that produced it, its quality grade, the model version where a model produced it, and whether a person reviewed it. Predictions are served as predictions and are not presented as verified.

Endpoints

publicNo key required

GET/v1/openapi.json

This document

    GET/v1/vocabulary

    Hypotheses, review mechanisms, reason codes, triage bands and signals, decision sources, rule versions, review roles, confidence levels, effects, statuses, evidence types, history kinds

    • 200the vocabulary the assessment uses

    cases:readCase snapshot

    GET/v1/me

    The calling key: partner, plan, effective scopes, rate limit and monthly quota (any active key)

    • 200partner, key {id, label, expires_at}, plan {id, name}, scopes[], tiers {cases, reports}, rate_per_min, quota {limit, used, remaining, resets_at}

    GET/v1/health

    Liveness, ledger counts and freshness (any active key)

    • 200ok, version, assessment_version, preview_signing, cases_total, cases_updated_24h, evidence_total, decisions_total, reviews_total, last_case_update, ledger_watermark, detections_replicated_to, detections_total, ledger_lag_s, replication_lag_s, last_case_update_age_s, reports_total, reports_recovered, reports_updated_24h, reports_replicated_to

    GET/v1/cases

    Cases, newest-updated first, keyset-paged; each carries the assessment headline (full with expand=assessment)

    • sincequeryISO 8601; rows at or after this instant
    • statusqueryone status or a comma list
    • stackquerys1 | s2s1 radar oil cases, s2 optical material cases; both when omitted
    • bandqueryattribution:read. One triage band or a comma list of INVESTIGATE, WATCH and LOOKALIKE_SIGNALS; radar cases whose latest triage decision holds that band.
    • bboxquerylon0,lat0,lon1,lat1 in EPSG:4326; order-insensitive
    • limitqueryPage size. Maximum 200, or 100 when expand is set.
    • cursorqueryopaque next_cursor from the previous page
    • expandquerycomma list of evidence,decisions,reviews,assessment (needs ledger:read; caps limit at 100). assessment = the full assessment per case instead of the headline
    • 200Page + cases[]

    GET/v1/cases/{case_id}/preview

    Preview PNG (302 to a signed URL valid 1 h; ?redirect=false returns {url, expires_at})

    • case_idpath
    • 302redirect to the file
    • 404no preview
    • 503signing not configured

    ledger:readEvidence ledger

    GET/v1/cases/{case_id}

    One case; the full assessment at ledger:read and above, the headline at cases:read

    • case_idpath
    • expandquerycomma list of evidence,decisions,reviews,assessment (needs ledger:read; caps limit at 100). assessment = the full assessment per case instead of the headline
    • 200
    • 404

    GET/v1/cases/{case_id}/assessment

    The assessment alone

    • case_idpath
    • 200

    GET/v1/cases/{case_id}/evidence

    Full evidence chain with provenance and per-row relevance

    • case_idpath
    • 200

    GET/v1/cases/{case_id}/decisions

    Decision trail as transitions, oldest first

    • case_idpath
    • 200

    GET/v1/cases/{case_id}/reviews

    Independent reviews

    • case_idpath
    • 200

    GET/v1/changes

    Change feed, oldest first: cases, evidence, decisions and reviews with ledger:read; report entries with reports:read.

    • sincequeryISO 8601; rows at or after this instant
    • cursorqueryopaque next_cursor from the previous page
    • limitqueryPage size. Maximum 1000.
    • kindsquerycomma list of case,evidence,decision,review,report; without it the feed carries every kind the key is entitled to
    • 200

    reports:readField reports

    GET/v1/reports

    In-situ reports, newest-updated first, keyset-paged

    • sincequeryISO 8601; rows at or after this instant
    • statusqueryreported | recovered
    • scenequerycomma list of beach,nature,urban,at_sea
    • bboxquerylon0,lat0,lon1,lat1 in EPSG:4326; order-insensitive
    • limitqueryPage size. Maximum 200, or 100 with reports:annotations.
    • cursorqueryopaque next_cursor from the previous page
    • 200Page + reports[]

    GET/v1/reports/{report_id}

    One report

    • report_idpath
    • 200
    • 404

    labels:readTraining labels

    GET/v1/labels

    Detection-scoped verified labels with provenance

    • sincequery
    • channelqueryground_truth_link | app_confirmation | community_review
    • training_eligiblequery
    • cursorquery
    • limitquery

      GET/v1/image-labels

      Report-image annotations with provenance

      • sourcequery
      • reviewedquery
      • training_eligiblequery
      • cursorquery
      • limitquery

        GET/v1/images/{id}

        Report image (302 to the file; labels:read)

        • idpath
        • redirectquery

          Parameters

          Shared across endpoints.

          sincequerydate-time/v1/cases, /v1/changes, /v1/reports
          ISO 8601; rows at or after this instant
          limitqueryinteger/v1/cases
          Page size. Maximum 200, or 100 when expand is set. Default 50.
          limitqueryinteger/v1/changes
          Page size. Maximum 1000. Default 500.
          cursorquerystring/v1/cases, /v1/changes, /v1/reports
          opaque next_cursor from the previous page
          expandquerystring/v1/cases, /v1/cases/{case_id}
          comma list of evidence,decisions,reviews,assessment (needs ledger:read; caps limit at 100). assessment = the full assessment per case instead of the headline
          bboxquerystring/v1/cases, /v1/reports
          lon0,lat0,lon1,lat1 in EPSG:4326; order-insensitive
          case_idpathuuid
          report_idpathuuid
          limitqueryinteger/v1/reports
          Page size. Maximum 200, or 100 with reports:annotations. Default 50.

          Objects

          Response fields, as published in the OpenAPI document.

          Error

          • errorstring
          • required_scopestring

          Scores

          s1 cases carry detector_score, decision_source, p_oil_corpus, champion_* and challenger_*; s2 cases carry material_score

          • material_scorenumber | nulls2 only: Stage 2 adjudicator output for the detected class; ranks, is not a probability
          • detector_scorenumber | nullThe score of the Stage 2 model named in decision_source. It ranks candidates and is not a probability.
          • decision_sourcestring | nulls1 only. The Stage 2 model whose score decided: challenger is the fine tuned model, champion the frozen model, champion_large a candidate of 10 km² or more that the frozen model scored higher. Dates at /v1/vocabulary under decision_sources.
          • champion_scorenumber | nulls1 only. The frozen Stage 2 model's score for the same candidate.
          • champion_spreadnumber | null
          • p_oil_corpusnumber | nullIsotonic calibration of detector_score for the deciding model, fitted on scenes held out of training. Valid in corpus and before adjudication.
          • challenger_scorenumber | nulls1 only. The fine tuned Stage 2 model's score for the same candidate.
          • challenger_spreadnumber | null
          • ensemble_spreadnumber | null
          • notestring

          Ref

          what an assessment entry points at; every claim is traceable to a ledger row or to the detection

          • kindstring
          • iduuidnull at cases:read (the snapshot carries no row ids) and for the verdict
          • typestringevidence type, for evidence refs

          Relevance

          what one input means for one hypothesis

          • refany
          • hypothesisstring
          • effectstring
          • reasonstringcites the fields and thresholds used
          • source_classstringDetector outputs are retained for traceability but do not contribute to hypothesis scoring.

          EvidenceRelevance

          • hypothesisstring
          • effectstring
          • reasonstring
          • source_classstringPresent when the row is not an observation: MEMORY rows are interpretation, GROUND_TRUTH rows adjudication.

          Hypothesis

          a nature-level explanation of the observed feature with its score (support − contradiction, detector excluded)

          • hypothesisstring
          • labelstring
          • detector_originbooleantrue for the family the detector itself claims (OIL_FILM, FLOATING_MATERIAL)
          • scoreinteger
          • supportinteger
          • contradictioninteger
          • independent_observationsinteger
          • review_rankinteger | nullwhere the latest independent review ranked this family, if it did
          • rule_flagsarrayreason codes of the latest rule decision that speak for this family

          MissingEvidence

          • evidencestring
          • statusstring
          • reasonstring
          • would_discriminatearray

          Contradiction

          every material contradiction stays visible

          • kindstring
          • detailstring
          • againststring
          • refany
          • itemsarrayattribution:read: the reviewer's own conflict statements

          HistoryEntry

          one dated event; status-moving entries carry from_status / to_status / changed so every transition is reconstructable

          • atdate-time
          • kindstring
          • from_statusstring | null
          • to_statusstring
          • changedboolean
          • refany
          • summarystring
          • typestring
          • qualitystring
          • effectsarray
          • rule_versionstring
          • reason_codesarray
          • reason_meaningsarray
          • bandstringattribution:read: the band of a triage decision
          • triage_signalsarraythe triage signals that hold, filtered by scope
          • rolestring
          • modelstring
          • top_hypothesisstring | null
          • optical_readingstring | null
          • concursboolean | null

          Assessment

          Derived, versioned, deterministic. cases:read receives the headline (assessment_version, assessed_at, current_status, confidence, primary_hypothesis {hypothesis, label, support, contradiction}, conclusion); ledger:read receives everything; attribution:read adds `attribution`.

          • assessment_versionstring
          • assessed_atdate-time
          • current_statusstring
          • confidencestringcategorical and rule-derived, never a probability; see /v1/vocabulary
          • confidence_basisstring
          • contestedbooleana tie between hypotheses, or the tracks (rules, review, second reading) disagree
          • based_onobject
          • primary_hypothesisanynull when not assessable
          • alternative_hypothesesarrayevery family the evidence or a review touched, best first
          • untested_hypothesesarrayfamilies nothing on file bears on
          • supporting_evidencearray
          • contradicting_evidencearray
          • neutral_evidencearray
          • missing_evidencearray
          • contradictionsarray
          • conclusionstringbounded: names the primary hypothesis, what supports and contradicts it, what is not excluded, the case status, and the disclaimer
          • limitationsarray
          • historyarray
          • attributionobjectattribution:read only: vessel_source {support, contradiction, evidence[]}, rule_flags, source_hypotheses (mechanism-level, ranked, with evidence_for / evidence_against), second_reading, reviewer_conflicts, reviewer_missing, triage {band, rule_version, decision_id, decided_at, signals}

          Case

          With cases:read: identifiers, timestamps, status, position, scores, the newest context per evidence type, rule_flags, verdict, preview and the assessment headline. With ledger:read: gate_reason, status_reason, geometry, detector_features, evidence_counts, decision_count, review_count, the full assessment (on the single-case route, or with expand=assessment) and any expanded arrays. With attribution:read: triage, the latest triage decision of a radar case. stack s1 is a Sentinel-1 radar oil case; s2 is a Sentinel-2 optical material case with material_class set and material_score in scores.

          • iduuid
          • detection_iduuid
          • scene_idstring
          • stackstring
          • material_classstring | nulls2 only: macroalgae, floating_debris, organic_material
          • observed_atdate-time
          • ingested_atdate-time
          • updated_atdate-time
          • statusstring
          • area_m2number | null
          • lonnumberDecimal degrees; 3 decimals with cases:read, 5 with ledger:read.
          • latnumber
          • scoresany
          • windobject | null
          • wavesobject | null
          • contextobject | null
          • recurrenceobject | null
          • cross_detectionobject | null
          • optical_coverageobject | null
          • verdictobject | null
          • rule_flagsarrayReason codes that fired in the latest rule decision, filtered by scope. Meanings are listed in /v1/vocabulary under reason_codes.
          • triageobject | nullattribution:read. The latest triage decision of a radar case: band, rule_version, decision_id and decided_at. Band meanings are listed in /v1/vocabulary under triage.
          • assessmentany
          • previewobject
          • disclaimerstring
          • gate_reasonstring | null
          • status_reasonstring | nulloperator text; attribution segments removed below attribution:read
          • geometryobject | null
          • detector_featuresobject | null
          • evidence_countsobject
          • decision_countinteger
          • review_countinteger
          • evidencearray
          • decisionsarray
          • reviewsarray

          Evidence

          • iduuid
          • typestringWIND, WAVES, STATIC_CONTEXT, RECURRENCE, CROSS_DETECTION, OPTICAL_COVERAGE, FIELD_REPORT, MEMORY, GROUND_TRUTH; AIS, AIS_EVENTS and AIS_TRACK at attribution:read
          • sourcestring
          • source_uristring | null
          • qualitystringQuality grade A to D, assigned per source. C marks a provisional row that is re-checked; D marks a source that was queried and failed. Only rows graded A or B can support or contradict a hypothesis; C and D rows are recorded as neutral.
          • observed_atdate-time
          • retrieved_atdate-time
          • factsobject
          • relevancearraywhat this row means for each hypothesis it bears on

          Decision

          one rule-set evaluation or human verdict, as a transition

          • iduuid
          • statusstring
          • rule_versionstringlookalike-rules-0.x and triage-0.x (s1), material-rules-0.x (s2), human-verdict-1
          • reasonsobject | nullFlag to boolean; the flags that fired are listed in reason_codes. Vessel flags at attribution:read. A triage decision carries the lookalike flags it read and a triage object of signals; its band and the vessel derived signals are served at attribution:read. Human verdicts: {human_verdict: true, note}.
          • inputsobject | nullthe exact facts the rule set read: static_context, recurrence, wind, detector_features, area, score, axis_azimuth_deg, wind_alignment_deg; human verdicts: {prior_status, detector_score}
          • from_statusstring | null
          • changedboolean | null
          • reason_codesarray
          • reason_meaningsarray
          • summarystring | null
          • created_atdate-time

          Review

          An independent review of the case. Reviews do not change case status.

          • iduuid
          • rolestring
          • modelstring
          • prompt_versionstring
          • concursboolean | nulloptical_second only. Derived by comparison rather than reported by the reviewer: true when the top-ranked mechanism equals that of the primary review.
          • optical_readingstring | null
          • primary_review_idstring | null
          • created_atdate-time
          • hypothesis_familiesarraythe ranking as nature-level families (ledger:read)
          • conflict_countinteger
          • missing_countinteger
          • hypothesesarrayattribution:read: ranked mechanisms with evidence_for[] and evidence_against[]
          • image_notesstring
          • optical_notesstring
          • missingarrayattribution:read: discriminators the reviewer asked for
          • conflictsarrayattribution:read: contradictions the reviewer flagged between image and data
          • comparisonobject

          Change

          • kindstring
          • iduuid
          • case_iduuidnull for report entries
          • atdate-time
          • detailobjectcase: {status, stack}; evidence: {type, quality, source}; decision: {status, rule_version, from_status, changed, reason_codes}, with band on a triage decision at attribution:read; review: {role, model, prompt_version, top_hypothesis (family at ledger:read, mechanism at attribution:read), concurs}; report: {status, scene, country}

          Report

          One in-situ report. reports:read fields always; reports:annotations adds annotations and analysis and serves the position at 5 decimals.

          • iduuid
          • reported_atdate-time
          • statusstring
          • recovered_atdate-time
          • recovery_sourcestring | nulllegacy_flag: the previous platform marked the report recovered without a date
          • sourcestring
          • lonnumber3 decimals with reports:read, 5 with reports:annotations
          • latnumber
          • countrystring | null
          • citystring | null
          • protected_areaobject | null
          • eventobject | nullthe clean-up event the report belongs to
          • scenestring | nullscene class from the image model
          • impactstring | null
          • severityinteger | null1 to 5
          • primary_typestring | nullthe reporter's or model's main class; see /v1/vocabulary item_classes
          • itemsobject | nullitem class → count, from the image model
          • categoriesobject | nullcoarse category → count
          • materialsarray | nullmaterials the reporter selected
          • weight_kgnumber | nullreported weight; null when only the placeholder value was recorded
          • photosarray
          • updated_atdate-time
          • disclaimerstring
          • annotationsarrayreports:annotations: per-image object detections {class, bbox [x, y, w, h] normalised, confidence} with source and model_version
          • analysisobject | nullreports:annotations: the model's scene labels, detected scene, pollution type counts, detected objects, people count, confidence and description

          Page

          • generated_atstring
          • countinteger
          • limitinteger
          • next_cursorstring | null

          Syncing

          Load the ledger once, then follow the change feed. Page the cases endpoint with the expansions required until next_cursor returns null.

          GET /v1/cases?expand=evidence,decisions,reviews,assessment&limit=100

          Then begin the change feed from a point several minutes before the load started, follownext_cursor to the end, and poll that final cursor to remain current. Overlap the initial since and deduplicate by id: entries are ordered by their own timestamp, and an entry committed late may carry a timestamp earlier than a cursor taken in the interim.

          GET /v1/changes?since=2026-09-08T00:00:00Z&limit=1000

          Retrieve a case again on any change entry referring to it. Each entry identifies the record that changed, permitting exact retrieval and deduplication, and carries detail specific to its kind: a decision entry reports the status produced and the status it replaced, so a status change is visible in the feed itself.

          No freshness bound is guaranteed. Where the processing node falls behind, responses continue to be served from the evidence on record, the change feed becomes quiet, and items marked pending under missing_evidence do not advance. Detections continue to accumulate upstream and are processed in order once the node resumes. ledger_lag_s in the health response reports the age of the most recent detection ingested: values in minutes are expected, values in hours indicate that the node is behind.

          Errors

          400
          A malformed parameter. The parameter at fault is named in error.
          401
          The key is missing or unrecognised.
          403
          The key is disabled, or the endpoint requires a scope the key does not hold. required_scope names it.
          404
          Unknown endpoint or identifier, or no preview exists for the case.
          429
          Rate limit exceeded.
          503
          File signing is not configured on the deployment.

          Conventions

          Base URL
          Issued with the key.
          Timestamps
          ISO 8601 in UTC. observed_at is the satellite acquisition, ingested_at the entry of the detection into the store, updated_at the most recent change to the case, and assessed_at the derivation of the assessment. since is inclusive.
          Identifiers
          UUIDs. detection_id is stable across systems, and each assessment entry references a record that can be retrieved directly.
          Coordinates
          EPSG:4326, longitude before latitude, as in GeoJSON.
          Paging
          Keyset cursors. A page shorter than limit is the final page and carries a null next_cursor.
          Rate limits
          120 requests per minute per organisation. Failed authentication is limited to 30 per minute per address, and the public documents to 60.
          Freshness
          Not guaranteed. Intake and enrichment run every 15 minutes and rule sets and reviews every 30. ledger_lag_s in the health response reports how far behind the ledger is.
          Versioning
          The path carries the version. Added fields and endpoints do not change it; removals and renames would. Assessment rules carry a separate assessment_version, incremented whenever a rule changes.

          Reading the scores

          Scores are model outputs. They rank candidates and do not measure or confirm the presence of oil, floating material or any material type, and no score identifies a source. Every response describing a detection carries a disclaimer field stating the applicable limitation for its sensor. Confidence is derived separately and is not a score.

          detector_score
          Raw output of the deployed detector model on a radar case. A ranking quantity, not a probability.
          p_oil_corpus
          detector_score under a calibration fitted on scene-held-out labelled data. Valid within the corpus and prior to adjudication.
          material_score
          The equivalent quantity on an optical case: adjudicator output for the detected material class. A ranking quantity, not a probability.
          challenger_score
          A second model scoring the same candidate in shadow. Not used in production decisions.
          ensemble_spread
          Disagreement within the deployed ensemble. Higher values indicate a less reliable score, and the assessment records this at 0.05 and above.

          Changes

          Additive changes do not alter the version in the path. Removals and renames would.

          9 September 2026
          Freshness reporting in the health response: ledger_lag_s, replication_lag_s and last_case_update_age_s, with the processing cadence documented under Syncing.
          8 September 2026
          The assessment layer. Each case carries an assessment comprising supporting, contradicting and neutral evidence, missing evidence and its status, a derived confidence with its basis, contradictions, a constrained conclusion, limitations and a reconstructable history. Evidence records carry their relevance to each hypothesis, decisions are expressed as status transitions, and reviews as ranked hypothesis families. Adds expand=assessment, GET /v1/cases/{id}/assessment and GET /v1/vocabulary.
          8 September 2026
          Optical material cases. Sentinel-2 floating-material detections open cases with stack s2, a material class and a material score, evaluated under a separate rule set, with verdicts CONFIRMED_MATERIAL and CONFIRMED_NON_MATERIAL. Adds the stack filter on /v1/cases.
          8 September 2026
          Preview and asset signing, preview_signing in the health response, and publication of the OpenAPI document without a key.
          3 September 2026
          Scopes ledger:read and attribution:read. Evidence, decisions and reviews per case, the expand parameter, the change feed, preview routes, named 400 responses, and cursors terminating in null.

          Spec and keys

          The OpenAPI 3.1 document describes every endpoint on this page and imports into Postman, Insomnia or any client generator. It requires no key. The base URL is not included in the document and is issued with the key.

          curl -H "Authorization: Bearer $KEY" "$BASE/v1/health"

          $BASE is issued with the key. The health endpoint returns the assessment rule version, ledger counts, replication watermarks and ledger_lag_s, and is the most direct way to confirm that a key is active.