Skip to main content

Migrating from v1 to v2

warning

Public API v1 has reached end of life. Any request to a v1 endpoint (any path that doesn't start with /v2) now receives an HTTP 410 Gone response, with no grace period. If your integration still talks to v1, it is already failing — migrate now.

v2 lives under the /v2 path prefix, with its own interactive reference at api.flypix.ai/v2/docs. The v1 reference stays up at api.flypix.ai/ui so you can compare the two while you migrate, but none of its endpoints respond anymore.

This page covers two audiences:

  • Migrating straight from v1 — apply every change below.
  • Already on v2 before this update — early v2 only changed the /v2 prefix and otherwise kept v1's request/response shapes. This update changes those shapes in place, under the same /v2 prefix — there is no separate v3 to move to. If you adopted v2 before now, you still need to apply the raster/file changes below.

If you use the official SDK, read that page too — updating it is a separate step from anything on this page.

Rasters replace files as the primary identifier​

The biggest change in v2 is what you address directly: rasters, not files.

You may already be familiar with rasters from v1 — GET /rasters/for-file/{file_id} and friends returned a thin status object (raster_id, file_id, status) alongside the fuller file record. In v2, that raster object absorbs the metadata that used to live on the file (name, folder placement) and becomes the resource you look up, list, and delete directly. This also lets a raster exist without a backing file at all — a WMTS, external COG, or OpenStreetMap raster never had one, so trying to reach it through a file id never worked well anyway.

A file record itself is now just a stored artifact — the raw upload plus whatever processing produced from it. You still upload files and download them, but you no longer fetch, list, or delete them directly; you reach them through a raster's source.

BeforeTwo related objects
// GET /files/{file_id}
{
"file_id": "f_123",
"name": "scene.tif",
"project_id": "p_1",
"folder_id": null,
"tenant_id": "t_1",
"extension": "tif",
"size": 48213888,
"status": "READY",
"created_at": "2026-01-01T00:00:00Z"
}

// GET /rasters/for-file/{file_id}
[
{
"raster_id": "r_123",
"file_id": "f_123",
"cog_file_id": "f_456",
"project_id": "p_1",
"tenant_id": "t_1",
"status": "PROCESSED",
"created_at": "2026-01-01T00:05:00Z"
}
]
AfterOne object
// GET /v2/rasters/{raster_id}
{
"raster_id": "r_123",
"name": "scene.tif",
"project_id": "p_1",
"folder_id": null,
"tenant_id": "t_1",
"status": "PROCESSED",
"created_at": "2026-01-01T00:05:00Z",
"source": {
"type": "UPLOAD",
"uploaded_file_id": "f_123",
"processed_file_id": "f_456",
"reprojected_file_id": null
}
}

source.type is one of UPLOAD, WMTS, EXTERNAL_COG, or OSM. Only UPLOAD rasters carry file ids at all, nested under source — they were never available for the other source types.

Endpoint changes​

Purposev1 (and pre-update v2)v2 now
Get / delete a rasterGET/DELETE /files/{file_id}GET/DELETE /v2/rasters/{raster_id}
Get several by idPOST /files/by-idsPOST /v2/rasters/get-by-ids
List for a projectGET /files/for-project/{project_id}GET /v2/rasters/for-project/{project_id}
List for a folderGET /files/for-folder/{folder_id}GET /v2/rasters/for-project/{project_id}?folder_id=...
Look up by uploaded fileGET /rasters/for-file/{file_id}removed — new uploads return the raster_id directly, see below. There is no v2 lookup from an existing file_id back to its raster, so remap any file ids you stored under v1 (see Remapping file ids you already stored)
Get a viewer-ready linkGET /files/{file_id}/visibleremoved — get the raster, then request a download link for its source.processed_file_id
List vector layersGET /vectors/for-file/{file_id}GET /v2/vectors/for-raster/{raster_id}
Create a vector layerPOST /vectors/ (file_id in body)POST /v2/vectors/ (raster_id in body)
List regionsGET /regions/for-file/{file_id}GET /v2/regions/for-raster/{raster_id}
Create regionsPOST /regions/{file_id}POST /v2/regions/{raster_id}
List inferencesGET /inferences/for-file/{file_id}GET /v2/inferences/for-raster/{raster_id}
Apply a modelPOST /models/{model_id}/apply (file_id in body)POST /v2/models/{model_id}/apply (raster_id in body)
Estimate a model applicationPOST /models/{model_id}/apply/estimate (file_id in body)POST /v2/models/{model_id}/apply/estimate (raster_id in body)

A region's own response shape changed the same way: the file_id field it used to carry is now raster_id.

New in v2​

These have no v1 equivalent — you don't need them to migrate, but they're new tools worth knowing about:

  • GET /v2/rasters/for-project/{project_id}/tree — a project's full folder structure with the raster ids in each folder, in one call.
  • POST /v2/models/change-detection/apply — triggers change detection between two rasters directly (raster_id_a, raster_id_b).
  • POST /v2/{vectors,models,inferences,folders}/get-by-ids — batch lookups by id for each of those resources (the raster equivalent is the rename of POST /files/by-ids listed above).

Uploading returns a raster id directly​

Before
// POST /files/upload
{
"file_id": "f_123",
"status": "UPLOADED"
}
After
// POST /v2/files/upload
{
"raster_id": "r_123",
"status": "UPLOADED"
}

POST /v2/files/upload and POST /v2/files/upload-from-url now return the newly created raster's id directly instead of a file id — there's no lookup step between uploading and having a raster_id to work with. Poll GET /v2/rasters/{raster_id} until status reaches PROCESSED. If you need the underlying file (for example, to build a download link), read it off the raster's source.uploaded_file_id once processing completes.

Remapping file ids you already stored​

The section above covers new uploads — the harder case is a v1 integration that already has file_ids persisted in its own database, from before this migration. There is no v2 endpoint that takes a file_id and returns its raster, so page through the project's rasters and match on the id yourself:

GET /v2/rasters/for-project/{project_id}?limit=200&offset=0
GET /v2/rasters/for-project/{project_id}?limit=200&offset=200
...

For each raster returned, compare your stored file_id against source.uploaded_file_id (only UPLOAD-source rasters have one). Once matched, store the raster's own raster_id going forward and stop keying anything off the file id.

Lists are now paginated​

GET /v2/rasters/for-tenant/{tenant_id}, for-project/{project_id}, the equivalent models and inferences endpoints, and GET /v2/folders/for-folder/{folder_id} / for-project/{project_id} now accept offset and limit query parameters, and default to limit=200 when none is given. v1 never documented or let you control this, so if you rely on getting everything back in a single call, pass an explicit limit (and page with offset) instead of assuming the response is complete.

The same endpoints also accept optional filter (comma-separated field:operator:value, with eq, ne, lt, le, gt, ge, like, in operators) and sort (field:asc or field:desc) parameters, scoped to a small allow-list of fields per resource (for rasters: status, name, created_at, folder_id).

What stayed the same​

  • Downloading a file — GET /v2/files/{file_id}/download is unchanged apart from the /v2 prefix: still keyed by file_id, still returns the same time-limited link. It's the only operation still addressed by file id — you now get that id from a raster's source field rather than from the upload response.
  • Authentication (the ApiKey header), the error response shape, projects, folders (aside from the pagination params above), payments, users, GeoSense, and every vector operation keyed by vector_id (features, annotations, class management, and the GeoJSON/GPKG/Shapefile upload endpoints).

Migration checklist​

  1. Point every request at /v2/... — v1 paths return 410 Gone.
  2. Replace any file_id-keyed call for vectors, regions, inferences, or model application with its raster_id equivalent.
  3. Read the raster_id straight off the upload response instead of looking it up afterward — the old GET /rasters/for-file/{file_id} lookup is gone.
  4. Add limit/offset to any list call you expect to return more than 200 items.
  5. Add the /v2 prefix to download calls — otherwise they're unaffected.
  6. If you use the official SDK, make sure you're on the current release — a version predating this migration calls operations that no longer exist. See that page for what changed.