---
title: "Look up a person's property by slug"
method: GET
path: "/users/{owner}/properties/{property}"
tags: ["Public", "Public properties"]
---

# Look up a person's property by slug

`GET /users/{owner}/properties/{property}`

## Request

- Base URL: `https://api.purplegrain.com/api/v1`
- URL: `https://api.purplegrain.com/api/v1/users/{owner}/properties/{property}`
- Auth: one of:
  - none
  - HTTP bearer

Look up one property of a person, by their handle and the property slug, in one call:
the visitor view of the place, its mapped paddocks, its mobs, its tasks and its records.
Works with no credentials when the property is public or shared by link (pass `share`).
A stranger with no credentials gets **404**. A signed-in caller who may not see it gets **403**.

The address is the web address with the API prefix, and the web address's `.json` form is
this call with the `include` below. `resolveLink` is the step that turns a pasted link
into these slugs.

* Visibility is the property's own, as for `resolveLink`: members read it, anyone reads a
  public property, and a link-shared one needs its `share` token. A caller with no credentials
  who may not read it gets a **404**, the same as for one that does not exist; a signed-in caller
  who may not gets a **403**.
* Only paddocks **with a boundary** are listed, and only rows filed on a listed paddock or mob
  (or on the property itself) are returned: nothing from archived or unmapped assets, nothing
  from another property.
* It follows the shared-link privacy rules: the place is the town and state, never the street
  or postcode, and nothing says who a task was shared with. The treatment register is never in it.
* Cacheable for a minute for callers with no credentials.

## Path parameters

- `owner` string, required
- `property` string, required

## Query parameters

- `include` string
- `share` string

## Response `200`

The property, with the requested sections.

- PublicPropertyResponse: A property as a visitor reads it. The sections named in `include` are present, and only those. Everything here follows the shared-link rules: the place is the town and state, never the street or postcode; nothing from archived or unmapped paddocks or from archived mobs; nothing about sharing with contractors; no emails or phone numbers.
  - `id` string
  - `name` string
  - `slug` string
  - `visibility` 'private' | 'link' | 'public'
  - `owner` object
    - `kind` 'organization' | 'user'
    - `slug` string
    - `name` string
  - `web_path` string: The property's own address on the web.
  - `location` string, nullable: Town and state, e.g. `Antwerp VIC`. Null when the label is only a street.
  - `area_ha` number, nullable
  - `centroid_lat` number, nullable
  - `centroid_lon` number, nullable
  - `boundary` PublicPropertyRing[], nullable: The outline as an array of rings (one per polygon part); null when none is drawn.
    - array[]: One polygon part as an array of `[lng, lat]` pairs (closed ring, longitude first), the same wire format as every other boundary — never GeoJSON.
      - number[]
  - `boundary_source` string, nullable
  - `paddock_count` integer
  - `mob_count` integer
  - `paddocks` PublicPropertyPaddock[]
    - `id` string
    - `name` string
    - `slug` string
    - `area_ha` number, nullable
    - `land_use` string, nullable
    - `current_crop` string, nullable
    - `boundary` PublicPropertyRing[], nullable: The outline as an array of rings (one per polygon part); null when none is drawn.
      - array[]: One polygon part as an array of `[lng, lat]` pairs (closed ring, longitude first), the same wire format as every other boundary — never GeoJSON.
        - number[]
    - `last_record_at` string, date-time, nullable
    - `open_task_count` integer
    - `withholding` PublicPropertyWithholding, nullable: Present only while a withholding date is still ahead. A mob carries the two drench dates, a paddock the two spray dates.
      - `task_id` string
      - `record_id` string
      - `safe_for_slaughter_on` string, date, nullable
      - `export_eligible_on` string, date, nullable
      - `safe_to_graze_on` string, date, nullable
      - `safe_to_harvest_on` string, date, nullable
      - `products` string[]
  - `mobs` PublicPropertyMob[]
    - `id` string
    - `name` string
    - `slug` string
    - `head_count` integer, nullable
    - `paddock_id` string, nullable
    - `paddock` string, nullable
    - `last_record_at` string, date-time, nullable
    - `open_task_count` integer
    - `withholding` PublicPropertyWithholding, nullable: Present only while a withholding date is still ahead. A mob carries the two drench dates, a paddock the two spray dates.
      - `task_id` string
      - `record_id` string
      - `safe_for_slaughter_on` string, date, nullable
      - `export_eligible_on` string, date, nullable
      - `safe_to_graze_on` string, date, nullable
      - `safe_to_harvest_on` string, date, nullable
      - `products` string[]
  - `tasks` PublicPropertyTask[]: The newest 300 at most.
    - `id` string
    - `title` string
    - `asset_name` string, nullable: The paddock or mob it is about; null for work on the property itself.
    - `asset_kind` 'paddock' | 'mob', nullable
    - `parent_id` string, nullable
    - `sequential` boolean
    - `completed_at` string, date-time, nullable
  - `records` PublicPropertyRecord[]: The newest 300 at most.
    - `id` string
    - `task_id` string, nullable
    - `asset_name` string, nullable
    - `asset_kind` 'paddock' | 'mob', nullable
    - `type` string, nullable: The operation type, free text by design (`spray`, `sow`, `drench`, `move_stock`, ...).
    - `date` string, date, nullable
    - `title` string
    - `by` string, nullable: The operator's name as entered. Never an email or a phone number.
    - `source` string, nullable: How it was captured (`voice`, `typed`, `agent`, `import`).
    - `notes` string, nullable
    - `photos` string[]
    - `drench` DrenchRead: The drench of a task or record. `safe_for_slaughter_on` and `export_eligible_on` are DERIVED (never stored) from the completion date plus the longest WHP / ESI among named products, and null while the task is open or until a named product carries a withholding period.
      - `id` string: The DrenchRecord id — the same before and after the task is completed.
      - `head` integer
      - `products` DrenchProductRead[]
        - `id` string
        - `name` string, nullable: What went in the gun. Blank is valid — a drench recorded before anyone said what it was.
        - `active` string, nullable: Label active constituent, e.g. `Abamectin 1 g/L`.
        - `batch` string, nullable: Batch number from the pack. Null when it was not recorded. Never invented.
        - `expiry` string, date, nullable: Expiry date on the pack, `YYYY-MM-DD`. Null when it was not recorded. Never invented.
        - `dose` string, nullable: As entered, e.g. `5 mL / 20 kg`.
        - `dose_value` number, nullable: The number in the dose, e.g. 5. Only what the caller sent; never parsed from `dose`.
        - `dose_unit` 'mL' | 'L' | 'g' | 'kg', nullable: Unit of `dose_value`.
        - `dose_basis` 'per_head' | 'per_kg' | 'per_mob', nullable: What `dose_value` is per.
        - `whp_days` integer: Withholding period, days.
        - `esi_days` integer: Export slaughter interval, days.
        - `position` integer: Order the products were entered in.
      - `safe_for_slaughter_on` string, date, nullable
      - `export_eligible_on` string, date, nullable
    - `spray` SprayRead: The spray of a task or record. `safe_to_graze_on` and `safe_to_harvest_on` are DERIVED (never stored) from the completion date plus the longest grazing / harvest WHP among named products, and null while the task is open or until a named product carries a value above zero for that period.
      - `id` string: The SprayRecord id — the same before and after the task is completed.
      - `area_ha` number, nullable: Hectares sprayed. Defaults to the paddock's area when the child is created without one and again when the task closes; null when the paddock has no area either.
      - `products` SprayProductRead[]
        - `id` string
        - `name` string, nullable: What went in the tank. Blank is valid — a spray recorded before anyone said what it was.
        - `active` string, nullable: Label active constituent, e.g. `Clopyralid 300 g/L`.
        - `batch` string, nullable: Batch number from the pack. Null when it was not recorded. Never invented.
        - `rate` string, nullable: As entered, e.g. `300 mL / ha`.
        - `grazing_whp_days` integer: Grazing withholding period, days.
        - `harvest_whp_days` integer: Harvest withholding period, days.
        - `position` integer: Order the products were entered in.
        - `role` 'herbicide' | 'fungicide' | 'insecticide' | 'adjuvant', nullable: What the product is in the tank.
        - `expiry` string, date, nullable: Expiry date on the pack, `YYYY-MM-DD`. Never invent one; unset prints `not recorded`.
        - `rate_value` number, nullable
        - `rate_unit` 'g' | 'kg' | 't' | 'mL' | 'L' | 'seeds' | '%', nullable: Unit of `rate_value`. A rate with a number and no unit is refused (422).
        - `rate_basis` 'ha' | 'head' | '100_kg_seed' | '100_l' | 'total', nullable: What the rate is per.
        - `esi_days` integer
        - `egi_days` integer
        - `eafi_days` integer
        - `do_not_graze` boolean: The label says DO NOT graze. Recorded on the spray and shown on the record; it gives the paddock no status, since it has no date.
        - `product_id` string, nullable: Optional link to the catalogue; the values here are copied at save.
      - `safe_to_graze_on` string, date, nullable
      - `safe_to_harvest_on` string, date, nullable
      - `method` 'boom' | 'boomless' | 'aerial' | 'drone' | 'spot' | 'weed_wiper' | 'knapsack' | 'airblast', nullable: How it was applied.
      - `water_rate_l_ha` number, nullable
      - `nozzle` string, nullable: Brand, model and size, as entered.
      - `pressure_kpa` integer, nullable: Boom pressure, kPa.
      - `boom_height_m` number, nullable
      - `speed_kmh` number, nullable
      - `droplet_category` 'extremely_fine' | 'very_fine' | 'fine' | 'medium' | 'coarse' | 'very_coarse' | 'extremely_coarse' | 'ultra_coarse', nullable: Droplet size category.
      - `no_spray_zone_m` integer, nullable: Downwind no-spray zone kept, metres.
      - `re_entry_note` string, nullable: Re-entry period, worker safety, informational.
      - `neighbour_drift` boolean, nullable: Drift from a neighbour was a factor.
      - `do_not_graze` boolean: A named product's label says DO NOT graze. Recorded on the spray; it gives the paddock no status, since it has no date.
      - `weather_readings` SprayWeatherReadingRead[]
        - `id` string
        - `read_at` string, date-time, nullable: When it was taken, an ISO 8601 time.
        - `wind_kmh` union: Wind speed, km/h.
          - number
          - string
        - `gust_kmh` union: Gust, km/h.
          - number
          - string
        - `wind_dir` string, nullable: Compass point, e.g. `SW`.
        - `temp_c` number, nullable: Temperature, degrees C.
        - `rh_pct` integer, nullable: Relative humidity, per cent.
        - `delta_t` number, nullable: Delta T.
        - `cloud_pct` integer, nullable: Cloud cover, per cent.
        - `rain_mm` union: Rain, mm.
          - number
          - string
        - `inversion_observed` boolean, nullable: An inversion was observed.
        - `source` string, nullable: On-site, or a named station with its distance.
        - `position` integer

## Other responses

- `403`: Signed in, but not allowed to see the property.
- `404`: Not found, or not visible to a caller with no credentials.

---

[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/06540345bbbc?raw)
