28 KiB
API Contracts v1
This document freezes the first API shape. Codex may add implementation details but must not rename these routes without updating this file and the frontend API client.
API principles
- Base path:
/api/v1. - JSON by default.
- GeoJSON accepted for geometries where possible.
- Long processing tasks return a job or analysis run record instead of blocking.
- Error responses use the shared
ApiErrorschema.
Shared schemas
ApiError
{
"error": "string",
"message": "human readable message",
"details": {},
"request_id": "optional string"
}
GeoJsonGeometry
Any valid GeoJSON geometry object. V1 primarily expects Polygon and MultiPolygon for areas.
BoundingBox
{
"min_x": 0.0,
"min_y": 0.0,
"max_x": 0.0,
"max_y": 0.0,
"crs": "EPSG:4326"
}
Health
GET /health
Returns service status.
{
"status": "ok",
"service": "geointel-backend",
"version": "0.1.0"
}
GET /api/v1/system/capabilities
Returns enabled feature flags and tool availability.
{
"postgis": true,
"rasterio": true,
"geopandas": true,
"yolo": false,
"sam": false,
"grb": "planned",
"sentinel": "planned",
"providers": [
{
"provider_name": "grb",
"display_name": "GRB",
"authority_level": "authoritative",
"supported_layers": ["buildings", "roads", "parcels"],
"supported_geometry_types": ["Polygon", "MultiPolygon", "LineString", "MultiLineString"],
"supported_query_modes": ["area"],
"fetch_signature": "POST /api/v1/external/grb/fetch",
"configured": false,
"status": "not_configured",
"limitation_message": "GRB live WFS/download integration is not configured in Sprint 7B.",
"attribution": "Digitaal Vlaanderen - Basiskaart Vlaanderen (GRB)",
"license_note": "Use must follow Digitaal Vlaanderen open data and attribution terms.",
"not_configured_reason": "Provider integration is not configured yet"
}
]
}
Projects
GET /api/v1/projects
Returns all projects.
POST /api/v1/projects
Request:
{
"name": "Geel building detection demo",
"description": "Detect buildings and validate against GRB",
"region": "Kempen"
}
Response: ProjectRead.
GET /api/v1/projects/{project_id}
Returns one project with summary counts.
PATCH /api/v1/projects/{project_id}
Updates name/description/region.
DELETE /api/v1/projects/{project_id}
Soft-delete in V1 preferred. Hard-delete only if storage cleanup is also implemented.
Areas
GET /api/v1/projects/{project_id}/areas
Returns areas for a project.
POST /api/v1/projects/{project_id}/areas
Request:
{
"name": "Geel Centrum AOI",
"geometry": {"type": "Polygon", "coordinates": []},
"crs": "EPSG:4326"
}
Backend responsibilities:
- Validate geometry.
- Repair trivial polygon issues if safe.
- Store geometry in PostGIS.
- Calculate area in square meters using projected CRS.
- Store bbox.
Datasets
POST /api/v1/projects/{project_id}/datasets/upload
Multipart upload.
Fields:
file: dataset file.dataset_type:vector,geojson(legacy),raster.source: free text, e.g.user_upload,grb,osm.dataset_role:source,derived, orreference(defaultsource).source_name: optional source identity, e.g.manual,grb,osm; reference uploads default tomanualwhen omitted.reference_layer_name: optional reference layer label, e.g.buildings; only retained for reference datasets.area_id: optional.
Response: DatasetRead with extracted metadata if supported.
Vector uploads remain stored as original files and are also persisted into vector_features as queryable PostGIS state.
GET /api/v1/projects/{project_id}/datasets
List datasets.
GET /api/v1/projects/{project_id}/datasets/{dataset_id}
Return metadata.
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/metadata/refresh
Re-extract metadata.
GET /api/v1/projects/{project_id}/datasets/{dataset_id}/vector/inspect
Return a wrapped vector inspection payload with metadata, storage summary and feature summary.
GET /api/v1/projects/{project_id}/datasets/{dataset_id}/vector/summary
Return vector summary data only.
GET /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/metadata
Return raster metadata profile for supported raster uploads.
If raster processing is unavailable:
code: RASTER_PROCESSING_UNAVAILABLE
message: Raster processing unavailable. Install rasterio and GDAL-compatible drivers to enable raster metadata extraction.
GET /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/inspect
Return raster inspect wrapper payload.
GET /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/stats
Return raster band statistics payload.
If raster processing dependencies are unavailable:
- code:
RASTER_PROCESSING_UNAVAILABLE - message: dependency-specific unavailable message.
GET /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/preview
Preview readiness for raster layers.
If preview dependencies are unavailable:
- code:
RASTER_PROCESSING_UNAVAILABLE - message:
Raster preview unavailable...
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/clip
Clip raster by selected area. Returns a 202-style accepted job payload through the job wrapper (jobs create/read flow).
If raster processing dependencies are unavailable:
- code:
RASTER_PROCESSING_UNAVAILABLE - message:
Raster processing unavailable. Install rasterio and GDAL-compatible drivers to enable raster processing operations.
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/reproject
Reproject raster dataset to another CRS.
Input:
target_crs(default:EPSG:31370)resampling(nearest,bilinear,cubic; defaultnearest)output_name
Returns a job payload with derived dataset id in result.output_dataset_id.
Failure modes:
- code:
INVALID_PARAMETERSfor bad CRS or resampling - code:
INVALID_DATASET_CRSwhen source raster CRS is missing - code:
RASTER_PROCESSING_UNAVAILABLEwhen rasterio is unavailable
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/indices/ndvi
Compute NDVI from raster band pairs.
Input:
nir_band(positive integer, 1-based)red_band(positive integer, 1-based)output_name(optional)
Returns a job payload with derived dataset id in result.output_dataset_id.
Failure modes:
- code:
INVALID_PARAMETERSfor non-positive/non-integer band indices - code:
INVALID_PARAMETERSfor band index outside source band count - code:
INVALID_DATASET_TYPEwhen source is not raster - code:
RASTER_PROCESSING_UNAVAILABLEwhen rasterio or numpy is unavailable
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/indices/ndwi
Compute NDWI from raster band pairs.
Input:
nir_band(positive integer, 1-based)green_band(positive integer, 1-based)output_name(optional)
Returns a job payload with derived dataset id in result.output_dataset_id.
Failure modes:
- code:
INVALID_PARAMETERSfor non-positive/non-integer band indices - code:
INVALID_PARAMETERSfor band index outside source band count - code:
INVALID_DATASET_TYPEwhen source is not raster - code:
RASTER_PROCESSING_UNAVAILABLEwhen rasterio or numpy is unavailable
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/indices/ndbi
Compute NDBI from raster band pairs.
Input:
nir_band(positive integer, 1-based)swir_band(positive integer, 1-based)output_name(optional)
Returns a job payload with derived dataset id in result.output_dataset_id.
Failure modes:
- code:
INVALID_PARAMETERSfor non-positive/non-integer band indices - code:
INVALID_PARAMETERSfor band index outside source band count - code:
INVALID_DATASET_TYPEwhen source is not raster - code:
RASTER_PROCESSING_UNAVAILABLEwhen rasterio or numpy is unavailable
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/raster/tile
Generate raster tiles and a manifest for downstream processing. Returns a job payload with tile_set_id and manifest metadata.
If raster processing dependencies are unavailable:
- code:
RASTER_PROCESSING_UNAVAILABLE - message:
Raster processing unavailable. Install rasterio and GDAL-compatible drivers to enable raster processing operations.
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/vector/clip
Clip vector dataset to selected area.
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/vector/buffer
Apply buffer distance to vector features.
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/vector/intersect
Intersect source vector dataset with another vector dataset.
POST /api/v1/projects/{project_id}/datasets/{dataset_id}/vector/stats
Return vector stats (feature counts and geometry summary).
GET /api/v1/projects/{project_id}/datasets/{dataset_id}/vector/bbox
Return vector bounds and feature count.
Jobs
POST /api/v1/projects/{project_id}/jobs
Create a job.
GET /api/v1/projects/{project_id}/jobs
List jobs.
GET /api/v1/projects/{project_id}/jobs/{job_id}
Read job detail.
GET /api/v1/projects/{project_id}/jobs/{job_id}/status
Read simplified job status payload.
Provider registry
GET /api/v1/external/providers
Returns all configured provider capability descriptors.
GET /api/v1/external/providers/capabilities
Compatibility alias for listing provider capability descriptors.
GET /api/v1/external/providers/{provider_name}
Returns one provider capability descriptor.
GET /api/v1/external/providers/{provider_name}/layers
Returns the supported provider layers.
GET /api/v1/external/providers/{provider_name}/status
Returns configured/status/limitation fields.
POST /api/v1/external/providers/{provider_name}/import
Defines the future provider import contract. Sprint 7B does not perform live imports or write datasets.
Request:
{
"project_id": "uuid-or-local-id",
"area_id": "optional uuid-or-local-id",
"layers": ["buildings"],
"dataset_role": "optional source|reference"
}
GRB/OSM response:
{
"provider_name": "grb",
"status": "not_configured",
"message": "No live GRB import is configured in Sprint 7B.",
"requested_layers": ["buildings"],
"dataset_id": null,
"dataset_role": "reference",
"source_name": "grb"
}
Manual and fixture providers point callers to existing upload/fixture flows. No provider writes directly to vector_features; all future provider output must flow through DatasetService and VectorFeatureService.
External data fetchers
POST /api/v1/external/osm/fetch
Request:
{
"project_id": "uuid",
"area_id": "uuid",
"layers": ["buildings", "roads", "water", "green"]
}
POST /api/v1/external/grb/fetch
Request:
{
"project_id": "uuid",
"area_id": "uuid",
"layers": ["buildings"]
}
V1 may initially implement this as a service interface with a clear not_configured response until the exact WFS endpoint is wired.
Sprint 7B provider contract responses expose capabilities only. Providers must report:
{
"provider_name": "osm",
"display_name": "OpenStreetMap",
"authority_level": "contextual",
"supported_layers": ["buildings", "roads", "water", "landuse"],
"supported_geometry_types": ["Polygon", "MultiPolygon", "LineString", "MultiLineString"],
"supported_query_modes": ["area"],
"configured": false,
"status": "not_configured",
"limitation_message": "OSM live Overpass/download integration is not configured in Sprint 7B.",
"attribution": "OpenStreetMap contributors",
"license_note": "OpenStreetMap data is available under ODbL; attribution is required."
}
No GRB WFS, OSM Overpass or provider downloads are implemented in Sprint 7B.
Demo workflow
POST /api/v1/demo/workflow
Seeds an explicit offline demo workflow from local fixture files. This endpoint does not fetch live GRB/OSM data and does not run AI inference. It creates or returns:
- one demo project
- one demo AOI
- one fixture reference building dataset
- one fixture candidate/predicted building dataset
- one persisted QA/QC result with metric rows
The endpoint is idempotent for the named demo project.
Response:
{
"project_id": "uuid",
"area_id": "uuid",
"reference_dataset_id": "uuid",
"candidate_dataset_id": "uuid",
"quality_check_id": "uuid",
"metric_count": 6,
"status": "ready",
"message": "Demo workflow seeded from explicit local fixtures.",
"created": true
}
Analysis
Detection Lab
Sprint 8 implements Detection Lab foundation only. YOLO/PyTorch real inference is not enabled, no model is downloaded, and fixture detections require explicit fixture mode.
GET /api/v1/detection/models
Returns object-detection model capability descriptors.
{
"models": [
{
"model_id": "yolo-placeholder",
"display_name": "YOLO detector placeholder",
"framework": "ultralytics/pytorch",
"task_type": "object_detection",
"supported_classes": ["building", "road", "water", "landuse"],
"configured": false,
"status": "not_configured",
"limitation_message": "YOLO/PyTorch inference is not configured in Sprint 8; no model is downloaded or executed.",
"version": null
},
{
"model_id": "yolo-configured",
"display_name": "Configured YOLO detector",
"framework": "ultralytics/pytorch",
"task_type": "object_detection",
"supported_classes": ["building", "road", "water", "landuse"],
"configured": false,
"status": "not_configured",
"limitation_message": "YOLO is disabled. Set YOLO_ENABLED=true and YOLO_MODEL_PATH to a local model file to enable inference.",
"version": null
}
]
}
POST /api/v1/detection/run
Creates a detection job and detection analysis run. If the requested model is unavailable, the job and analysis run are marked failed with DETECTION_MODEL_UNAVAILABLE or DETECTION_DEPENDENCY_UNAVAILABLE.
Request:
{
"project_id": "uuid",
"dataset_id": "uuid",
"model_id": "yolo-placeholder",
"confidence_threshold": 0.5,
"class_filter": ["building"],
"tile_manifest_path": null,
"parameters_json": {}
}
Sprint 8B configured YOLO mode uses model_id: "yolo-configured". It requires:
YOLO_ENABLED=trueYOLO_MODEL_PATHpointing to an existing local model file- backend optional AI dependencies installed with
geointel-backend[ai] tile_manifest_pathpointing to an existing raster tile manifest generated by the raster tile operation
GeoIntel does not download model weights automatically. Configured YOLO runs read existing tile files from the manifest, convert YOLO pixel-space boxes to EPSG:4326 detection polygons and persist detections as first-class records.
Unavailable model response:
{
"analysis_run_id": "uuid",
"job_id": "uuid",
"project_id": "uuid",
"dataset_id": "uuid",
"model_id": "yolo-placeholder",
"status": "failed",
"detection_count": 0,
"error_code": "DETECTION_MODEL_UNAVAILABLE",
"message": "YOLO/PyTorch inference is not configured in Sprint 8; no model is downloaded or executed."
}
Validation errors:
INVALID_DATASET_TYPEwhen the dataset is not raster.DETECTION_MODEL_NOT_FOUNDwhen the model id is unknown.FIXTURE_MODE_REQUIREDwhenmanual-fixture-detectoris requested withoutparameters_json.fixture_mode=true.DETECTION_TILE_MANIFEST_REQUIREDwhenyolo-configuredis requested withouttile_manifest_path.DETECTION_TILE_MANIFEST_NOT_FOUNDwhen the provided manifest path does not exist.DETECTION_TILE_MANIFEST_INVALIDwhen the manifest cannot be parsed or lacks tile metadata.DETECTION_TILE_LIMIT_EXCEEDEDwhen the manifest exceedsYOLO_MAX_TILES.DETECTION_DEPENDENCY_UNAVAILABLEwhen YOLO dependencies are not installed.DETECTION_MODEL_LOAD_FAILEDwhen the local model file exists but cannot be loaded.
Fixture detector mode is test/demo-only. It persists only explicit parameters_json.fixture_detections entries and is never invoked automatically.
GET /api/v1/detection/runs/{analysis_run_id}
Returns one detection analysis run.
GET /api/v1/detection/runs
Returns detection analysis runs, optionally filtered by project_id and dataset_id.
GET /api/v1/detection/runs/{analysis_run_id}/detections
Returns persisted detections for a detection analysis run. Optional filters:
dataset_idclass_namemin_confidence
GET /api/v1/detection/datasets/{dataset_id}/detections
Returns persisted detections for a raster dataset. Optional filters:
analysis_run_idclass_namemin_confidence
GET /api/v1/detection/detections/{detection_id}
Returns one persisted detection.
GET /api/v1/detection/runs/{analysis_run_id}/geojson
Returns persisted detections for a run as a GeoJSON FeatureCollection. Geometry comes from persisted PostGIS detection geometry in EPSG:4326.
Each feature includes:
detection_idclass_nameconfidencemodel_namemodel_versionanalysis_run_iddataset_idjob_idsource_tile_pathbbox_json
GET /api/v1/detection/datasets/{dataset_id}/geojson
Returns persisted detections for a dataset as a GeoJSON FeatureCollection. Optional filters match the detection list endpoint.
POST /api/v1/detection/runs/{analysis_run_id}/qa/reference
Compares persisted detection geometries from an analysis run against persisted vector_features from a reference vector dataset.
Request:
{
"reference_dataset_id": "uuid",
"iou_threshold": 0.5,
"class_name": "building",
"min_confidence": 0.5
}
Response persists a quality_check and metrics rows through the existing QA/QC persistence architecture and returns:
precisionrecallf1_scoremean_ioufalse_positivesfalse_negativesquality_check_id
If the reference dataset has no persisted vector features, the endpoint returns REFERENCE_FEATURES_NOT_FOUND. It does not calculate fake QA metrics.
POST /api/v1/analysis/building-stats
Input: area + vector building layer.
POST /api/v1/analysis/object-detection
Request:
{
"project_id": "uuid",
"area_id": "uuid",
"dataset_id": "uuid",
"model_id": "optional uuid",
"classes": ["building"],
"confidence_threshold": 0.35,
"tile_size": 640,
"overlap": 64
}
Response: AnalysisRunRead.
POST /api/v1/analysis/segmentation
Same pattern as object detection, but output includes masks and polygonized geometries.
Segmentation Lab
Sprint 9 implements Segmentation Lab foundation only. Real SAM and YOLO-seg inference are not enabled, no model is downloaded, and fixture segmentations require explicit fixture mode.
GET /api/v1/segmentation/models
Returns segmentation model capability descriptors:
segmentation-placeholder:not_configuredfixture-segmenter: configured for explicit test/demo fixtures onlyyolo-seg-configured:not_configuredsam-configured:not_configured
POST /api/v1/segmentation/run
Creates a segmentation job and segmentation analysis run. If the requested model is unavailable, the job and analysis run are marked failed with SEGMENTATION_MODEL_UNAVAILABLE.
Request:
{
"project_id": "uuid",
"dataset_id": "uuid",
"model_id": "segmentation-placeholder",
"confidence_threshold": 0.5,
"class_filter": ["vegetation"],
"tile_manifest_path": null,
"parameters_json": {}
}
Fixture segmenter mode is test/demo-only. It persists only explicit parameters_json.fixture_segmentations entries when parameters_json.fixture_mode=true; it is never invoked automatically and does not represent production inference.
Validation errors:
INVALID_DATASET_TYPEwhen the dataset is not raster.SEGMENTATION_MODEL_NOT_FOUNDwhen the model id is unknown.FIXTURE_MODE_REQUIREDwhenfixture-segmenteris requested withoutparameters_json.fixture_mode=true.INVALID_FIXTURE_SEGMENTATIONSwhen fixture payloads are not a list.INVALID_FIXTURE_GEOMETRYwhen fixture geometry is empty, invalid or not Polygon/MultiPolygon.
GET /api/v1/segmentation/runs
Returns segmentation analysis runs, optionally filtered by project_id and dataset_id.
GET /api/v1/segmentation/runs/{analysis_run_id}
Returns one segmentation analysis run.
GET /api/v1/segmentation/runs/{analysis_run_id}/segmentations
Returns persisted segmentation records for a segmentation analysis run. Optional filters:
dataset_idclass_namemin_confidence
GET /api/v1/segmentation/datasets/{dataset_id}/segmentations
Returns persisted segmentation records for a raster dataset. Optional filters:
analysis_run_idclass_namemin_confidence
GET /api/v1/segmentation/segmentations/{segmentation_id}
Returns one persisted segmentation record.
GET /api/v1/segmentation/runs/{analysis_run_id}/geojson
Returns persisted segmentations for a run as a GeoJSON FeatureCollection. Geometry comes from persisted PostGIS segmentation geometry in EPSG:4326.
Each feature includes:
segmentation_idclass_nameconfidencearea_m2model_namemodel_versionanalysis_run_iddataset_idjob_idsource_tile_pathtile_indexmask_pathbbox_jsonprovenance_json
GET /api/v1/segmentation/datasets/{dataset_id}/geojson
Returns persisted segmentations for a dataset as a GeoJSON FeatureCollection. Optional filters match the segmentation list endpoint.
POST /api/v1/segmentation/runs/{analysis_run_id}/qa/reference
Compares persisted segmentation geometries from an analysis run against persisted vector_features from a reference vector dataset.
Request:
{
"reference_dataset_id": "uuid",
"iou_threshold": 0.5,
"class_name": "vegetation",
"min_confidence": 0.5
}
Response persists a quality_check and metrics rows through the existing QA/QC persistence architecture and returns precision, recall, F1, mean IoU and false positive/negative counts.
If the segmentation run has no persisted geometries, the endpoint returns SEGMENTATIONS_NOT_FOUND. If the reference dataset has no persisted vector features, it returns REFERENCE_FEATURES_NOT_FOUND. It does not calculate fake QA metrics.
POST /api/v1/analysis/change-detection
Compares two persisted vector datasets in the same project and returns a synchronous job envelope. This is a lightweight V1 foundation for added/removed object review, not a temporal run-history engine.
Request:
{
"source_dataset_id": "uuid",
"target_dataset_id": "uuid",
"iou_threshold": 0.8,
"include_unchanged": true
}
Response is a canonical API envelope containing a JobRead payload. On success,
result_json contains:
{
"source_dataset_id": "uuid",
"target_dataset_id": "uuid",
"source_feature_count": 2,
"target_feature_count": 2,
"added_count": 1,
"removed_count": 1,
"unchanged_count": 1,
"iou_threshold": 0.8,
"warnings": [],
"generated_at": "2026-06-16T00:00:00Z",
"geojson": {
"type": "FeatureCollection",
"features": []
}
}
Change detection prefers persisted vector_features. If an older vector dataset
has no persisted vector rows, it falls back to the stored GeoJSON artifact and
adds a warning to result_json.warnings. Supported comparable geometry types are
Polygon and MultiPolygon; point/line geometries return UNSUPPORTED_GEOMETRY.
GeoJSON feature properties include:
change_type:added,removedorunchangedsource_dataset_idtarget_dataset_idsource_feature_idtarget_feature_idiou
Limitations:
- No live GRB/OSM/Sentinel fetching.
- No fake object lifecycle classification.
- No
changedclassification without durable object ids/versioning. - No first-class change table yet; the current output is stored in job
result_jsonand rendered in the frontend map.
QA/QC
POST /api/v1/qa/detections-vs-reference
Request:
{
"candidate_dataset_id": "uuid",
"reference_dataset_id": "uuid",
"iou_threshold": 0.5,
"area_id": "optional uuid"
}
Response is wrapped in the job envelope. On success, result_json includes precision, recall, F1, mean IoU, false positives, false negatives and quality_check_id.
Sprint 7A persists the QA/QC result as:
jobs: execution state.quality_checks: domain result.metrics: individual measurements.
Future Detection and Segmentation flows may add an analysis_run_id path without replacing persisted quality checks.
GET /api/v1/projects/{project_id}/quality-checks
Lists persisted QA/QC quality checks for a project with metric rows.
Response:
{
"items": [
{
"id": "uuid",
"project_id": "uuid",
"job_id": "uuid-or-null",
"analysis_run_id": "uuid-or-null",
"candidate_dataset_id": "uuid-or-null",
"reference_dataset_id": "uuid",
"check_type": "demo_candidate_vs_reference",
"status": "ok",
"score": 0.5,
"parameters_json": {},
"findings_json": {},
"metrics": [
{
"metric_key": "precision",
"metric_value": 0.5
}
]
}
],
"total": 1,
"limit": 50,
"offset": 0
}
Exports
POST /api/v1/exports/geojson
Export detections, segmentations or vector layer to GeoJSON.
Dataset vector export request:
{
"export_kind": "dataset",
"dataset_id": "uuid",
"name": "optional-basename"
}
Detection run export request:
{
"export_kind": "detection_run",
"analysis_run_id": "uuid",
"name": "optional-basename"
}
Segmentation run export request:
{
"export_kind": "segmentation_run",
"analysis_run_id": "uuid",
"name": "optional-basename"
}
Response persists an exports row and writes a deterministic JSON artifact:
{
"export_id": "uuid",
"path": "storage/exports/{project_id}/datasets/{target}/{name}.geojson",
"status": "ready",
"export_type": "dataset_geojson",
"metadata_json": {
"source": "dataset",
"feature_count": 0
}
}
Vector dataset exports use the stored dataset GeoJSON. Detection and segmentation exports use persisted first-class geometry records and the existing Detection/Segmentation GeoJSON conversion services. Raster datasets are rejected for dataset GeoJSON export.
POST /api/v1/exports/metadata
Exports project metadata JSON for projects, datasets, persisted QA/QC summary rows and existing export history.
{
"project_id": "uuid",
"name": "optional-basename"
}
GET /api/v1/exports/projects/{project_id}/exports
Lists persisted export records for a project.
GET /api/v1/exports/{export_id}
Returns one persisted export record.
GET /api/v1/exports/{export_id}/content
Returns the stored JSON artifact content through the standard API envelope.
GET /api/v1/exports/{export_id}/download
Downloads the stored JSON/GeoJSON export artifact as a raw file response with
application/json content type and a Content-Disposition attachment
filename. This endpoint intentionally does not use the JSON envelope because
it is a browser/file-download path; callers that need canonical API JSON should
use /content.
POST /api/v1/exports/yolo
Export annotations/detections to YOLO format.
POST /api/v1/exports/report
Creates a lightweight HTML project report artifact from persisted project, dataset, QA/QC summary and export history state. This does not create a PDF and does not introduce a report designer.
{
"project_id": "uuid",
"name": "optional-basename"
}
Response persists an exports row with export_type: project_report_html. Download the report through:
GET /api/v1/exports/{export_id}/download
PDF/report-designer functionality can be added after core GeoAI workflows work.