---
title: "Attach searched parcels to a property"
method: POST
path: "/properties/{property_id}/parcels"
tags: ["Properties"]
---

# Attach searched parcels to a property

`POST /properties/{property_id}/parcels`

## Request

- Base URL: `https://api.purplegrain.com/api/v1`
- URL: `https://api.purplegrain.com/api/v1/properties/{property_id}/parcels`
- Auth: HTTP bearer

Stores parcels the farmer picked. external_ids must come from a recent searchParcels
result for this property's state. Geometry in the body is ignored. The server copies
the geometry it fetched. Sending the same external_id again updates that parcel and
does not create a second row. An id that is not in a recent search is 409
parcel_not_in_search. An empty list is 422 parcel_ids_required.

An assistant sends confirm true. Needs edit access to the property. The response is
the property's parcels after the write, as plain JSON.

## Path parameters

- `property_id` string, required

## Request body

- AttachParcelsModelAttributes: Flat request body (Content-Type application/json). Attribute fields live directly under data.
  - `data` object, required
    - `external_ids` string[]: Ids returned by searchParcels. Geometry is not accepted.

## Response `201`

The property's parcels, including the ones just attached.

- PropertyParcelsResponse
  - `property_id` string, uuid, required
  - `parcels` Parcel[], required
    - `id` string, uuid, nullable: Present once the parcel is stored on the property. Omitted on a search candidate.
    - `external_id` string, required: The cadastral id from that state's parcel service. NSW lot/DP, a Vicmap SPI, a Queensland lotplan, or a Tasmanian PID.
    - `state` 'NSW' | 'VIC' | 'QLD' | 'SA' | 'WA' | 'TAS' | 'NT' | 'ACT', nullable
    - `source` string, nullable: Which public service the geometry came from. nsw_spatial, vicmap_parcel, qld_dcdb or tas_list.
    - `lot` string, nullable
    - `plan` string, nullable
    - `lot_plan` string, nullable: Lot and plan as one label, when the service provides them.
    - `area_ha` number, nullable: Area in hectares, from the parcel service when it publishes one.
    - `geometry` ParcelGeometry, required: GeoJSON in WGS84, longitude first. A Polygon, or a MultiPolygon when the parcel has more than one part. Holes are not stored.
      - `type` 'Polygon' | 'MultiPolygon', required
      - `coordinates` unknown[], required
        - unknown
  - `_meta` OnboardingMeta
    - `onboarding` Onboarding: Where the account in scope is in setting up a farm. A suggestion: reads are never refused because a step is missing. `next_step` is null once every step is done.
      - `status` 'not_started' | 'in_progress' | 'complete'
      - `completed_steps` string[]
      - `next_step` 'create_team' | 'create_property' | 'map_boundaries' | 'map_paddocks' | 'create_blocks' | 'add_mobs' | 'first_record', nullable
      - `skill` string
      - `skill_url` string
      - `agent_hint` string: Plain-language instruction, including a short fallback the agent can follow without the skill.

## Other responses

- `401`: Unauthorized
- `403`: Forbidden
- `404`: Not Found
- `409`: An external_id is not in a recent search.
- `415`: Unsupported Media Type — the request's `Content-Type` is `application/vnd.api+json` with a media type parameter the JSON:API media type does not allow (anything other than `ext` and `profile`; `; charset=utf-8` is the usual one). Send the bare media type. The error's `code` is `unsupported_media_type` and `source.header` is `Content-Type`. Until the switch is on (`JSONAPI_CONTENT_TYPE_PARAMS=reject`) such a request is let through and logged; the operation documents the response it will have.
- `422`: No external_ids were sent, or the property has no state.

## Changes

- **2026-10-30** `143d65e52617`: 1 info
  - added the non-success response with the status `415`
- **2026-10-30** `92c4663a1266`: 12 warning, 12 info
  - removed the optional property `_meta` from the response with the `409` status (media type: application/json)
  - removed the optional property `_meta` from the response with the `409` status (media type: application/vnd.api+json)
  - removed the optional property `_meta` from the response with the `422` status (media type: application/json)
  - removed the optional property `_meta` from the response with the `422` status (media type: application/vnd.api+json)
  - …20 more
- **2026-10-24** `e285768a8f1d`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/purplegrain/apis/purple-grain-api/changes/properties/:property_id/parcels/post.md)

---

[API](https://skmtc.dev/purplegrain/apis/purple-grain-api.md) - [All operations](https://skmtc.dev/purplegrain/apis/purple-grain-api/llms.txt) - [OpenAPI document](https://skmtc.dev/purplegrain/apis/purple-grain-api/revisions/e32f34ba218b?raw)
