Skip to content

Public API

GeoJibe's public REST API is the contract for the CLI and Python client. Browser, CLI, and SDK clients all use the same /api/v1 handlers, ownership rules, and business logic.

The official CLI is geojibe:

pipx install geojibe

See Command-line client and Python SDK.

Self-hosted installations (Dedicated and On-Premise) use this same API against the local user database. There is no central GeoJibe authentication service.

Environment variables

Reserve these names for the CLI and SDK:

export GEOJIBE_URL=https://<host>
export GEOJIBE_TOKEN=gjp_...

GEOJIBE_URL is the installation origin (no trailing slash). Do not hard-code a hosted GeoJibe URL — self-hosted deployments use their own host.

GEOJIBE_CONFIG_DIR optionally overrides the CLI/SDK config directory (the folder that contains config.toml). Normal installs do not set it.

Never put a token in a query string or URL path.

Authentication

Browser sessions continue to use the enciva_session cookie.

External clients authenticate with a Personal Access Token:

Authorization: Bearer $GEOJIBE_TOKEN

Tokens are created in Account → API Tokens. The full gjp_… value is shown once at creation. GeoJibe stores only a SHA-256 hash.

Session cookies are not accepted as Bearer credentials. A PAT cannot create or revoke other PATs; token management requires a browser session.

Expired and revoked tokens fail with HTTP 401. last_used_at is updated at most once per minute after a successful PAT authentication.

Authorization

A PAT belongs to one user and cannot see another user's Sources, Destinations, Jobs, Recipes, or Workspaces. Scopes only reduce that user's capabilities.

Scope Access
account:read Read the token owner's profile (GET /api/v1/auth/me)
sources:read List and get Sources, discover PostGIS schemas/tables, and list or inspect QFieldCloud/Mergin Maps projects
sources:write Create, update, delete, and test Sources
destinations:read List and get Destinations, and discover PostGIS schemas/tables
destinations:write Create, update, delete, and test Destinations
jobs:read List Jobs, get a Job, list Runs
jobs:write Create, update, enable, disable, and delete Jobs
jobs:run Run Now and retry a failed Run. Does not include jobs:read.
workspaces:read Get a Workspace, read its transformation state, preview source or transformed data/map, download its result, and read the transformation catalog. Does not include jobs:read.
workspaces:write Create a Workspace by uploading a dataset or importing a saved Source, and replace its transformation pipeline. Importing a saved Source also requires sources:read. Does not include jobs:write.
workspaces:run Convert a Workspace, or deliver its converted result to a saved Destination. Delivery also requires destinations:read. Does not include workspaces:read or jobs:run.
recipes:read List and get Recipes
recipes:write Create, update, and delete Recipes

There is no tokens:write scope in V1. Existing tokens keep only the scopes they were created with. Workspace scopes are not granted to tokens created before those scopes existed.

Jobs vs Workspaces

Jobs and Workspaces are different public resources.

Resource Meaning
Jobs Persistent automation. Can be scheduled and run repeatedly.
Workspaces Temporary interactive processing. Used for upload or saved-Source import → inspect → preview → convert → download or saved-Destination delivery. Automatically expire.

The browser Canvas still uses compatibility routes such as POST /api/v1/inspect, GET /api/v1/jobs/{id}/data-preview, and POST /api/v1/jobs/{id}/spatial-preview. Those paths are not the public external contract. External clients should use /api/v1/workspaces.

Jobs vs pipelines

Saved automation Jobs are the public persistent resource. The browser UI still calls /api/v1/pipelines/… internally; those routes remain as compatibility aliases.

Public clients should use:

Action Method Path Scope
List Jobs GET /api/v1/jobs jobs:read
Get Job GET /api/v1/jobs/{id} jobs:read
Create Job POST /api/v1/jobs jobs:write
Update Job PUT /api/v1/jobs/{id} jobs:write
Delete Job DELETE /api/v1/jobs/{id} jobs:write
Enable Job POST /api/v1/jobs/{id}/enable jobs:write
Disable Job POST /api/v1/jobs/{id}/disable jobs:write
Run Job POST /api/v1/jobs/{id}/run jobs:run
List Runs GET /api/v1/jobs/{id}/runs jobs:read
Get Run GET /api/v1/jobs/{id}/runs/{runId} jobs:read
Retry Run POST /api/v1/jobs/{id}/runs/{runId}/retry jobs:run
Reset Sync POST /api/v1/jobs/{id}/sync/reset jobs:write
Reinitialize Sync POST /api/v1/jobs/{id}/sync/reinitialize jobs:write

GET /api/v1/jobs/{id} returns a saved Job when the id matches one the caller owns. Canvas inspect/preview routes under /api/v1/jobs/{id}/… that are not in this table are not the public Job contract.

Create and update send JSON such as:

{
  "name": "Neighborhoods",
  "source_id": "…",
  "transform_mode": "sql",
  "sql": "SELECT * FROM source WHERE population > 1000",
  "output_format": "GeoJSON",
  "destination_id": "…",
  "destination_target": {
    "schema": "public",
    "table": "neighborhoods",
    "write_mode": "replace"
  },
  "schedule": {"kind": "daily", "timezone": "UTC", "hour": 2, "minute": 0}
}

transform_mode is manual, recipe, or sql.

Mode What you send
manual operations (and optional output_fields)
recipe recipe_id — GeoJibe snapshots the Recipe operations onto the Job
sql sql — one SELECT against source

SQL is a sibling field (sql), not an operation type. Python on a Job uses python_script and python_filename. Recipe edits after save do not change Jobs that already snapshotted that Recipe.

Account

Action Method Path Scope
Current user GET /api/v1/auth/me account:read

Token create, list, and revoke (/api/v1/account/tokens) require a browser session. A PAT cannot create or revoke other PATs.

Sources

Action Method Path Scope
List Sources GET /api/v1/sources sources:read
Get Source GET /api/v1/sources/{id} sources:read
Create Source POST /api/v1/sources sources:write
Update Source PUT /api/v1/sources/{id} sources:write
Delete Source DELETE /api/v1/sources/{id} sources:write
Test draft POST /api/v1/sources/test sources:write
Test saved POST /api/v1/sources/{id}/test sources:write

Create body:

{
  "name": "Public neighborhoods",
  "type": "url",
  "configuration": {"url": "https://example.com/neighborhoods.geojson"}
}

type is the Source type (url, http, s3, azureblob, gdrive, featureserver, postgis, sqlserver, mysql, oracle, bigquery, snowflake, geoserver, geonode, ogcfeatures, stac, ckan, hub, qfieldcloud, merginmaps). Configuration fields match the saved connection for that type. Secrets in GET/list responses are omitted.

Saved PostGIS Sources expose schema and table discovery. Omit schema to list schemas. Pass schema to list tables and views in that schema. Credentials stay on the server and are never returned.

Action Method Path Scope
Discover PostGIS GET /api/v1/sources/{id}/discover sources:read

Optional query: schema.

Response:

{
  "host": "db.example.com",
  "database": "gis",
  "schemas": ["public", "field"],
  "schema": "public",
  "tables": [
    {
      "schema": "public",
      "name": "neighborhoods",
      "has_geometry": true,
      "geometry_type": "Polygon"
    }
  ]
}

tables is omitted until schema is set. Typical errors: postgis_failed (connection, authentication, TLS, missing database, permission, timeout), invalid_source (not a PostGIS Source), source_not_found, forbidden.

QFieldCloud and Mergin Maps Sources can list and inspect projects. These are read operations:

Action Method Path Scope
List projects POST /api/v1/sources/{id}/projects sources:read
Inspect project POST /api/v1/sources/{id}/inspect-project sources:read

Destinations

Action Method Path Scope
List Destinations GET /api/v1/destinations destinations:read
Get Destination GET /api/v1/destinations/{id} destinations:read
Create Destination POST /api/v1/destinations destinations:write
Update Destination PUT /api/v1/destinations/{id} destinations:write
Delete Destination DELETE /api/v1/destinations/{id} destinations:write
Test draft POST /api/v1/destinations/test destinations:write
Test saved POST /api/v1/destinations/{id}/test destinations:write
Discover PostGIS GET /api/v1/destinations/{id}/discover destinations:read

Destination discovery uses the same engine and response shape as Source discovery. Omit schema to list schemas. Pass schema to list tables. Typical errors: postgis_failed, invalid_destination, destination_not_found, forbidden. There is no public draft-connection discover endpoint. Test a draft, save it, then discover.

Create body:

{
  "name": "Production PostGIS",
  "type": "postgis",
  "configuration": {
    "host": "db.example.com",
    "database": "gis",
    "username": "etl",
    "password": "…",
    "ssl_mode": "prefer"
  }
}

type is the Destination type (postgis, sqlserver, mysql, oracle, bigquery, snowflake, s3, azureblob, gdrive, sftp, hub, geoserver, geonode, webhook). Per-run targets (schema, table, object key) belong on the Job destination_target, not the saved Destination.

Hub browse helpers on /api/v1/sources/{id}/hub/… and /api/v1/destinations/{id}/hub/… (and the GeoServer/GeoNode listing helpers) are PAT-accessible with the matching Source or Destination scope. They are connection helpers, not Canvas inspect routes.

Recipes

Action Method Path Scope
List Recipes GET /api/v1/recipes recipes:read
Get Recipe GET /api/v1/recipes/{id} recipes:read
Create Recipe POST /api/v1/recipes recipes:write
Update Recipe PUT /api/v1/recipes/{id} recipes:write
Delete Recipe DELETE /api/v1/recipes/{id} recipes:write

Create body:

{
  "name": "Rename shape_len",
  "operations": [
    {"type": "rename_column", "from": "shape_len", "to": "perimeter"}
  ]
}

A Recipe stores Transform operations. It is not a Job.

Workspaces

A Workspace is a temporary processing context. Create one by uploading a local file or importing a saved Source you own. GeoJibe inspects it, you preview a layer, convert it, then download the result or deliver it to a saved Destination. The Workspace expires automatically (default 60 minutes; ENCIVA_JOB_TTL). Expired workspaces return job_expired. Files are removed by the existing cleanup. A saved Source does not make the Workspace persistent.

Typical PAT flow:

  1. POST /api/v1/workspaces — upload a file, or import a saved Source
  2. GET /api/v1/workspaces/{id} — read layers and metadata
  3. GET /api/v1/workspaces/{id}/data-preview?layer=… — sample source rows
  4. GET /api/v1/workspaces/{id}/spatial-preview?layer=… — source vector GeoJSON
  5. GET /api/v1/transformations — transformation catalog
  6. PUT /api/v1/workspaces/{id}/transformations — set the ordered pipeline
  7. GET /api/v1/workspaces/{id}/transform-preview?layer=… — transformed rows
  8. GET /api/v1/workspaces/{id}/transform-spatial-preview?layer=… — transformed GeoJSON
  9. POST /api/v1/workspaces/{id}/convert — convert using the stored pipeline
  10. GET /api/v1/workspaces/{id}/download — download the converted file or POST /api/v1/workspaces/{id}/deliver — publish it to a saved Destination

Download and delivery are independent. Convert first. Deliver does not convert with guessed defaults. If no converted output exists, delivery returns job_not_ready.

Preview is not a substitute for convert/download. Preview responses are truncated samples.

Uploads use the same size limit as Canvas: ENCIVA_MAX_UPLOAD_MB, default 256 MiB. Oversized uploads return upload_too_large with max_bytes in details.

Shapefiles must be uploaded as a ZIP of the companion files (.shp, .shx, .dbf, and .prj when available). Native multi-file shapefile upload is not part of this API.

Workspace IDs do not grant access. Another user's Workspace returns job_not_found (HTTP 404), the same as a missing id.

Action Method Path Scope
Transformation catalog GET /api/v1/transformations workspaces:read
Create Workspace POST /api/v1/workspaces workspaces:write (plus sources:read when importing a saved Source)
Get Workspace GET /api/v1/workspaces/{id} workspaces:read
Data Preview GET /api/v1/workspaces/{id}/data-preview workspaces:read
Spatial Preview GET /api/v1/workspaces/{id}/spatial-preview workspaces:read
Get transformations GET /api/v1/workspaces/{id}/transformations workspaces:read
Set transformations PUT /api/v1/workspaces/{id}/transformations workspaces:write
Transformed Data Preview GET /api/v1/workspaces/{id}/transform-preview workspaces:read
Transformed Spatial Preview GET /api/v1/workspaces/{id}/transform-spatial-preview workspaces:read
Convert Workspace POST /api/v1/workspaces/{id}/convert workspaces:run
Deliver result POST /api/v1/workspaces/{id}/deliver workspaces:run + destinations:read
Download result GET /api/v1/workspaces/{id}/download workspaces:read

POST /api/v1/workspaces accepts either:

  • multipart/form-data with field file — upload and inspect a local dataset
  • application/json with source_id and optional source_resource — import a saved Source you own
{
  "source_id": "…",
  "source_resource": {
    "schema": "public",
    "table": "neighborhoods"
  }
}

source_resource is the same per-use selector used by saved Jobs. URL and HTTP Sources do not need it. Types that select a table, object, layer, collection, or asset require it and return invalid_parameter or invalid_source when it is missing.

Supported import types: url, http, s3, azureblob, featureserver, postgis, sqlserver, mysql, oracle, bigquery, snowflake, geoserver, geonode, ogcfeatures, stac, hub.

gdrive, ckan, qfieldcloud, merginmaps, and duckdb are not available on this route.

The server loads and decrypts saved Source credentials. Workspace JSON, errors, and logs never include passwords, access keys, tokens, or private keys.

POST /api/v1/workspaces/{id}/deliver publishes the current converted output to a saved Destination:

{
  "destination_id": "…",
  "destination_target": {
    "remote_path": "/exports/neighborhoods.geojson",
    "write_mode": "replace"
  }
}

destination_target is the same per-delivery target used by saved Jobs (schema/table, object key, remote path, write mode, GeoServer layer, and so on). A successful response includes public destination and delivery metadata. Secrets are never returned.

Supported delivery types: postgis, sqlserver, mysql, oracle, bigquery, snowflake, s3, azureblob, sftp, hub, geoserver, geonode, webhook.

gdrive and duckdb are not available on this route. Download remains GET /api/v1/workspaces/{id}/download and is not a saved Destination.

Another user's Source, Destination, or Workspace id returns the existing non-enumerating 404 (source_not_found, destination_not_found, or job_not_found).

The JSON representation reuses the existing inspect/convert fields (status, filename, size, dataset type, format, driver, layers, fields, raster metadata, CRS, warnings, output, and errors). It also includes expires_at. Filesystem paths are never returned.

Data Preview

GET /api/v1/workspaces/{id}/data-preview returns a bounded attribute sample for one layer. Geometry is not required — non-spatial tables are valid targets.

Query parameters:

Parameter Required Notes
layer Multi-layer workspaces Omit only when the dataset has a single layer.
limit No Default 100. Hard maximum 500. Non-positive or non-numeric values return invalid_parameter.

Example:

{
  "workspace_id": "abc123",
  "layer": "apiary",
  "fields": [
    {"name": "nbr_of_boxes", "type": "Integer"},
    {"name": "bee_species", "type": "String"}
  ],
  "has_geometry": true,
  "geometry_type": "Point",
  "crs": "EPSG:3857",
  "row_count": 35,
  "preview_row_count": 35,
  "limit": 100,
  "truncated": false,
  "rows": [
    {"nbr_of_boxes": 4, "bee_species": "apis"}
  ]
}

preview_row_count is how many rows were returned. row_count is the layer feature/row count when known. truncated is true when the sample is shorter than the full table or hit the requested limit. Geometry cells are type labels (for example POINT), not WKT/WKB coordinates.

Spatial Preview

GET /api/v1/workspaces/{id}/spatial-preview returns vector features for map display. The selected layer must have geometry. A non-spatial table returns invalid_parameter (HTTP 400) explaining that the layer cannot be spatially previewed. The response is not empty GeoJSON.

Query parameters:

Parameter Required Notes
layer Multi-layer workspaces Omit only when the dataset has a single layer.

The existing preview engine reprojects a read-only sample to EPSG:4326 for standard web maps. The source dataset is not rewritten. source_crs is the layer CRS; preview_crs is always EPSG:4326. Coordinates in geojson are WGS 84 lon/lat.

GeoJSON is produced with GDAL RFC7946=YES, so Z/M dimensions (for example LineStringZM) are flattened to 2D (LineString). Feature properties are kept for identify/popup use. Filesystem paths and credentials are never included.

The server caps spatial preview at 2000 features. returned_count, feature_count, and truncated say whether the response is a sample.

Example:

{
  "workspace_id": "abc123",
  "layer": "apiary",
  "source_crs": "EPSG:3857",
  "preview_crs": "EPSG:4326",
  "returned_count": 35,
  "feature_count": 35,
  "truncated": false,
  "geojson": {
    "type": "FeatureCollection",
    "features": []
  }
}

Raster preview, QGIS WMS, and private Canvas job routes such as /api/v1/jobs/{id}/transform-preview are not part of this public Workspace contract.

Transformations

GET /api/v1/transformations is a server-driven capability catalog. Use the stable id values (for example simplify), not display name labels, as API identifiers. The catalog describes GeoJibe's existing operations — it does not add new ones.

PUT /api/v1/workspaces/{id}/transformations replaces the complete ordered pipeline. The JSON uses the same operation objects as Recipes and Jobs (type, column, from, to, tolerance, distance, and so on). Order is significant and is not reordered for vector operations.

{
  "layers": ["apiary"],
  "operations": [
    {"type": "rename_column", "from": "name", "to": "site"},
    {"type": "buffer", "distance": 25, "units": "source"}
  ]
}

{"operations": []} clears the pipeline. The uploaded source file is never overwritten.

Layer targeting. Operations do not carry a per-operation layer field. layers on the pipeline selects which layer(s) the operations apply to. A multi-layer dataset (for example bees.gpkg) requires layers when operations or SQL are set. A pipeline for apiary does not modify area. Geometry operations on a non-spatial table fail validation with invalid_transformation. Attribute and SQL operations may target non-spatial tables.

SQL. DuckDB SQL is a sibling field, not an operation type. It is mutually exclusive with operations. Queries must be a single SELECT against the source relation and use the existing SQL sandbox (no network, no filesystem reads outside the workspace, no credentials).

{
  "layers": ["Reviews"],
  "sql": "SELECT * FROM source WHERE comment IS NOT NULL"
}

Python. When stored, the script runs in the same isolated runtime as Canvas preprocess (python3 script.py <input> <output>, no network). It is applied to a temporary copy at preview/convert time. The original upload is not replaced.

Convert uses the currently stored pipeline. Every convert starts from the immutable upload plus the current definition — previous outputs are not stacked. output_format and target_crs remain convert-request fields.

Transformed Data Preview and Transformed Spatial Preview use the stored pipeline. Query parameters match source preview (layer, and limit for data). Spatial preview still reprojects a sample to EPSG:4326 for display only. Preview responses remain truncated samples; convert/download is the full result.

Workspace transformation state expires with the Workspace (ENCIVA_JOB_TTL).

Convert accepts JSON such as:

{
  "output_format": "GeoJSON",
  "target_crs": "EPSG:4326"
}

output_format values come from GET /api/v1/formats. target_crs is optional. Download returns Content-Disposition, Content-Length when known, and Content-Type: application/octet-stream.

The Workspace API requires a browser session or a PAT. It does not accept anonymous access. Failed requests return the standard JSON error envelope, not an HTML login page.

Formats

GET /api/v1/formats returns the server-driven GDAL format catalog (vector and raster input/output). It is public and does not require a PAT. Call it before presenting output-format choices. Do not hard-code format tables.

System

GET /api/v1/system returns non-sensitive runtime capabilities: GDAL version, driver counts, feature flags (for example raster processing), and the deployment edition. It is public. Treat container_image as an implementation detail; do not depend on it.

Secrets

GET and list responses for Sources and Destinations never include passwords, secret keys, private keys, API tokens, or credential JSON. Use flags such as has_password and has_secret_key.

Errors

Failed requests return:

{
  "error": {
    "code": "forbidden",
    "message": "Token does not have jobs:run scope."
  }
}

Typical status codes: 200, 201, 204, 400, 401, 403, 404, 409, 422, 500.

PostGIS discover failures use postgis_failed with a message for connection, authentication, TLS, missing database, missing schema/table, permission, or timeout. Responses never include passwords, PATs, or connection secrets.

Examples

Replace <host> with your installation. Do not paste real tokens into docs or shell history when you can avoid it.

Current user

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/auth/me"

List Sources

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/sources"

List Destinations

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/destinations"

List Jobs

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/jobs"

Get Job

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/jobs/<job-id>"

Run Job

curl \
  -X POST \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/jobs/<job-id>/run"

List Recipes

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/recipes"

List formats

curl \
  "$GEOJIBE_URL/api/v1/formats"

Create a Workspace

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -F "file=@example.gpkg" \
  "$GEOJIBE_URL/api/v1/workspaces"

Shapefiles must be a ZIP:

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -F "file=@parcels.zip" \
  "$GEOJIBE_URL/api/v1/workspaces"

Create a Workspace from a saved Source

curl \
  -X POST \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"source_id":"<source-id>"}' \
  "$GEOJIBE_URL/api/v1/workspaces"

Requires workspaces:write and sources:read. Add source_resource when the saved Source type needs a table, object, layer, collection, or asset.

Get a Workspace

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>"

Convert a Workspace

curl \
  -X POST \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"output_format":"GeoJSON"}' \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/convert"

Preview Workspace rows

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/data-preview?layer=apiary"

Non-spatial tables use the same endpoint:

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/data-preview?layer=Reviews&limit=50"

Preview Workspace features on a map

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/spatial-preview?layer=apiary"

List available transformations

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/transformations"

Set Workspace transformations

curl \
  -X PUT \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"layers":["apiary"],"operations":[{"type":"buffer","distance":25,"units":"source"}]}' \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/transformations"

Read the stored pipeline:

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/transformations"

Clear it with an empty replacement:

curl \
  -X PUT \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"operations":[]}' \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/transformations"

Preview transformed rows and geometry

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/transform-preview?layer=apiary"
curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/transform-spatial-preview?layer=apiary"

Deliver a Workspace result

curl \
  -X POST \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"destination_id":"<destination-id>","destination_target":{"remote_path":"/exports/result.geojson"}}' \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/deliver"

Requires workspaces:run and destinations:read. Convert must have completed first.

Download a Workspace result

curl \
  -H "Authorization: Bearer $GEOJIBE_TOKEN" \
  -o result.geojson \
  "$GEOJIBE_URL/api/v1/workspaces/<workspace-id>/download"