A Field is a geospatial land parcel within a Farm — its boundary, soil type, and the imagery/pricing actions that key off that boundary. This page covers what's specific to Fields. For the base URL, authentication, the response envelope, pagination, sharing, the foreign-key _id write convention, and soft delete, see Farm Management Overview.
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /field/ | List fields (cached) |
| POST | /field/ | Create a field (single object or bulk array) |
| GET | /field/FIELD_ID/ | Retrieve a single field (cached) |
| PUT | /field/FIELD_ID/ | Replace a field |
| PATCH | /field/FIELD_ID/ | Partially update a field |
| DELETE | /field/FIELD_ID/ | Soft delete a field |
GET /field/FIELD_ID/also has a side effect: if the field's crop history hasn't been populated yet, the retrieve request triggers an asynchronous job to fetch it. The response you get back won't include that data yet — pollcrop-history(below) or retrieve the field again afterward.
Auth
Requires a Bearer token — see Farm Management Overview for how to send one.
Each action also requires a dynamic permission on top of the token:
| Action | Required permission |
|---|---|
| List / Retrieve | field.view |
| Create | field.create |
| Update / Partial update | field.edit |
| Delete | field.delete |
A request with a valid token but missing the required permission gets an HTTP 403 with the structured body described in Farm Management Overview.
Create fields
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
name | string, max 255 | Yes | — | |
farm_id | integer (FK) | Yes | — | Must reference an existing farm — see the _id write convention in Farm Management Overview |
boundary | GeoJSON object | Yes | — | A full GeoJSON FeatureCollection; the server reads geometry from features[0] |
soil_type | integer | No | 1 |
Response-only fields
Beyond the fields above, a Field response also includes:
| Field | Notes |
|---|---|
area | Computed server-side from boundary — don't send it on create/update |
field_uuid | Server-generated UUID, set on creation |
latest_map_request_time | Set once a satellite map has ever been ordered for this field — see the update lock below |
cultivations | Nested list of this field's cultivations; nulled to [] when viewed via ?share=true unless the sharing grant covers sub-resources |
total_map_request | Nulled to null under the same ?share=true condition, unless the grant covers maps |
is_registered | Subscription-tier flag |
farm | Nested, read-only — see Farm Management Overview on the _id-for-write convention |
created_by | Nested, read-only — no created_by_id to write |
Updates lock once a map exists
PUT/PATCH /field/FIELD_ID/returns 409 Conflict if the field'slatest_map_request_timeis already set — i.e. once a satellite map has ever been ordered for it, its core data is locked:{ "status": "error", "message": "Modification not allowed: A map with this field already exists. Please create a new field.", "details": {} }There's no way to unlock an existing field once a map has been ordered against it — the workaround is to create a new field.
Bulk create
POST /field/ also accepts a JSON array of field objects instead of a single object. See Farm Management Overview for how Fields' bulk-error status code (402 Payment Required for a bulk array with any invalid item) differs from Farms', Cultivations', and Fertilization's (400 for both single and bulk-array validation failures). A single invalid object sent to POST /field/ still returns a plain 400, regardless of the bulk quirk.
Status codes
| Status | Trigger |
|---|---|
| 200 | List, retrieve, or update succeeded. |
| 201 | Create succeeded (single object or bulk array). |
| 204 | Delete succeeded (soft delete; no response body). |
| 400 | Validation failure on a single-object create. |
| 402 | Validation failure on a bulk-array create where any item is invalid — see Farm Management Overview. |
| 403 | Missing field.view / field.create / field.edit / field.delete permission. |
| 404 | Field not found (wrong FIELD_ID, wrong company, or already deleted). |
| 409 | Update blocked because a map already exists for this field — see above. |
Field-specific actions
Beyond core CRUD, the Field resource exposes several actions oriented toward satellite imagery and pricing rather than basic field management. These are real, live endpoints on the same
/field/FIELD_ID/...resource:
Method Path Purpose Permission slug GET /field/FIELD_ID/crop-history/?crop-name=Crop history for this field field.crop_historyGET /field/FIELD_ID/price/Pricing info for map ordering on this field field.priceGET /field/FIELD_ID/maps/Maps ordered for this field field.mapsGET /field/FIELD_ID/download/?format-type=geojson|shapefile&is-base64=Download the field boundary field.download_shapefileGET /field/FIELD_ID/available-image/Available satellite image dates field.available_image_dateGET /field/FIELD_ID/available-fused-image/Available fused-image dates field.available_fused_image_dateGET /field/FIELD_ID/season/SEASON_ID/profile/Field profile for a given season field.field_profile
downloadand bothavailable-image/available-fused-imageendpoints catch broad, unfiltered exceptions internally, so their status codes are approximate rather than precise on these specific actions:downloadreturns a bare 404 for any internal failure, not just "boundary not found," andavailable-image/available-fused-imageeach return 503 Service Unavailable for any internal failure, not just a genuine upstream outage. Don't treat those two status codes as a precise signal on these three actions specifically — inspect the response body (where present) rather than branching purely on status code.
Create request
curl -X POST https://backend.spacenus.de/api/v1.2/field/ \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "North Block",
"farm_id": 101,
"boundary": {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [[[13.4050, 52.5200], [13.4080, 52.5200], [13.4080, 52.5230], [13.4050, 52.5230], [13.4050, 52.5200]]]
}
}
]
},
"soil_type": 2
}'Response:
{
"status": "success",
"message": "Resource created successfully.",
"data": {
"id": 501,
"field_uuid": "3f9a2c1e-6b4d-4a2f-8e7a-1d5c9b0f4a22",
"name": "North Block",
"soil_type": 2,
"area": null,
"latest_map_request_time": null,
"total_map_request": 0,
"is_registered": false,
"boundary": {
"type": "FeatureCollection",
"features": [ ]
},
"farm": {
"id": 101,
"name": "North Ridge Farm"
},
"cultivations": [ ],
"created_by": {
"id": 42,
"name": "Jane Doe"
},
"created_at": "2026-08-19T10:20:00Z",
"updated_at": "2026-08-19T10:20:00Z"
}
}Retrieve response
{
"status": "success",
"message": "Operation successful.",
"data": {
"id": 501,
"field_uuid": "3f9a2c1e-6b4d-4a2f-8e7a-1d5c9b0f4a22",
"name": "North Block",
"soil_type": 2,
"area": "4.820",
"latest_map_request_time": "2026-08-20T09:00:00Z",
"total_map_request": 3,
"is_registered": true,
"boundary": {
"type": "FeatureCollection",
"features": [ ]
},
"farm": {
"id": 101,
"name": "North Ridge Farm"
},
"cultivations": [
{
"id": 900,
"season": { "id": 12, "name": "2026 Summer" },
"crop": { "id": 3, "name": "Wheat" }
}
],
"created_by": {
"id": 42,
"name": "Jane Doe"
},
"created_at": "2026-08-19T10:20:00Z",
"updated_at": "2026-08-20T09:00:00Z"
}
}