Migrating from v1 to v2
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
/v2prefix and otherwise kept v1's request/response shapes. This update changes those shapes in place, under the same/v2prefix — 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.
// 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"
}
]
// 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
| Purpose | v1 (and pre-update v2) | v2 now |
|---|---|---|
| Get / delete a raster | GET/DELETE /files/{file_id} | GET/DELETE /v2/rasters/{raster_id} |
| Get several by id | POST /files/by-ids | POST /v2/rasters/get-by-ids |
| List for a project | GET /files/for-project/{project_id} | GET /v2/rasters/for-project/{project_id} |
| List for a folder | GET /files/for-folder/{folder_id} | GET /v2/rasters/for-project/{project_id}?folder_id=... |
| Look up by uploaded file | GET /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 link | GET /files/{file_id}/visible | removed — get the raster, then request a download link for its source.processed_file_id |
| List vector layers | GET /vectors/for-file/{file_id} | GET /v2/vectors/for-raster/{raster_id} |
| Create a vector layer | POST /vectors/ (file_id in body) | POST /v2/vectors/ (raster_id in body) |
| List regions | GET /regions/for-file/{file_id} | GET /v2/regions/for-raster/{raster_id} |
| Create regions | POST /regions/{file_id} | POST /v2/regions/{raster_id} |
| List inferences | GET /inferences/for-file/{file_id} | GET /v2/inferences/for-raster/{raster_id} |
| Apply a model | POST /models/{model_id}/apply (file_id in body) | POST /v2/models/{model_id}/apply (raster_id in body) |
| Estimate a model application | POST /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 ofPOST /files/by-idslisted above).
Uploading returns a raster id directly
// POST /files/upload
{
"file_id": "f_123",
"status": "UPLOADED"
}
// 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}/downloadis unchanged apart from the/v2prefix: still keyed byfile_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'ssourcefield rather than from the upload response. - Authentication (the
ApiKeyheader), the error response shape, projects, folders (aside from the pagination params above), payments, users, GeoSense, and every vector operation keyed byvector_id(features, annotations, class management, and the GeoJSON/GPKG/Shapefile upload endpoints).
Migration checklist
- Point every request at
/v2/...— v1 paths return410 Gone. - Replace any
file_id-keyed call for vectors, regions, inferences, or model application with itsraster_idequivalent. - Read the
raster_idstraight off the upload response instead of looking it up afterward — the oldGET /rasters/for-file/{file_id}lookup is gone. - Add
limit/offsetto any list call you expect to return more than 200 items. - Add the
/v2prefix to download calls — otherwise they're unaffected. - 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.