> ## Documentation Index
> Fetch the complete documentation index at: https://docs.goliathdata.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Properties API

> Search properties, run saved filters, manage tags and lists, and skip-trace owners through the Goliath developer API

## About

Programmatic access to the property database: search by address, parcel, or
MLS id, fetch property details and attributes, run your saved property
filters, organize properties with tags and lists, and skip-trace owners.

All operations go through the developer API gateway — one endpoint, called by
`operationId`. If you haven't set up a key yet, start with the
[Developer API Overview](/developer-api/overview).

<Note>
  **Property ids**

  The search operations (`findProperties`, `findPropertiesByParcel`,
  `findPropertiesByMlsId`) return the property id to use everywhere else —
  pass it as-is to `getProperty`, `getRelatedProperties`, tag/list operations,
  and skip tracing.
</Note>

## Operations

### Lookup and search (`READ` scope)

| operationId              | What it does                                                                                                                                                                                                                                                                                                                   |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `getProperty`            | Fetch one property by id — address, skip-trace status, and signal recency.                                                                                                                                                                                                                                                     |
| `getPropertyOwners`      | Fetch a property's known people — owners and relatives from deed records and public-record signals, merged with your organization's skip-trace results. Names can appear without a trace; phone numbers (incl. DNC status) and emails are generally populated only after `skipTraceProperty`. Reading never consumes a credit. |
| `findProperties`         | Search properties by (partial) address. Returns address suggestions with the property id to use in `getProperty`.                                                                                                                                                                                                              |
| `findPropertiesByParcel` | Search properties by (partial) parcel id.                                                                                                                                                                                                                                                                                      |
| `findPropertiesByMlsId`  | Search properties by (partial) MLS id.                                                                                                                                                                                                                                                                                         |
| `getRelatedProperties`   | Batch property attributes by id — beds/baths/size, year built, last sale, estimated value, occupancy.                                                                                                                                                                                                                          |
| `getZoningCodes`         | List the zoning codes available for a location (state + city id or county FIPS).                                                                                                                                                                                                                                               |
| `searchCities`           | Find US cities by (partial) name — returns each match's `id`, `name`, and `state`. This is how you identify a city for a filter. Include the state in the term (e.g. `Memphis TN`) when a name is common. Capped at 10 matches.                                                                                                |
| `searchCounties`         | Find US counties by (partial) name — returns each match's `name`, `fullName`, `state`, and 5-digit `fips`. Include the state in the term (e.g. `Orange County FL`) when a name is common. Capped at 10 matches.                                                                                                                |

<Note>
  **Address/parcel/MLS searches are paginated**

  `findProperties`, `findPropertiesByParcel`, and `findPropertiesByMlsId` return up
  to **50** matches per call (a larger `limit` is clamped) but take an **`offset`**,
  and return `totalCount` + `hasMore` — so you can page through the full result set:
  send `offset: 0`, then `offset: 50`, and so on until `hasMore` is `false`. See
  [Result limits & truncation](/developer-api/overview#result-limits--truncation).
</Note>

### Saved filters (`READ` + `WRITE` scopes)

| operationId            | Scope   | What it does                                                                                                                                                                                                                                                                                                  |
| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `listPropertyFilters`  | `READ`  | List your saved property filters (id + name). The filter definition stays server-side.                                                                                                                                                                                                                        |
| `listFilterFieldNames` | `READ`  | The complete, compact vocabulary of filterable fields for `CONTACT` or `PROPERTY`. Use this to discover whether a field exists; unlike the full catalog, it fits in one response.                                                                                                                             |
| `listFilterFields`     | `READ`  | Full authoring metadata for selected fields — component, options, and `valueShapes`, including each mutually exclusive union arm and its required keys. `fieldIds` is required — the full catalog is too large for one response, so discover names with `listFilterFieldNames` first and narrow here.         |
| `getFilter`            | `READ`  | Fetch one saved filter by id **including its full `root` criteria tree** — the only operation that returns the tree, for both contact and property filters.                                                                                                                                                   |
| `filterProperties`     | `READ`  | Run a filter and paginate matches with `limit`/`offset`. Pass either a `filterId` (a saved filter) or a `filterTree` to run a tree without saving it. Returns a page plus `total`/`hasMore`.                                                                                                                  |
| `saveFilter`           | `WRITE` | Create a saved filter and get its id for `filterProperties`. Parses `root` strictly — an unknown field or invalid value rejects the save. Relay any returned `warnings`; they are non-fatal advisories about criteria such as same-named counties across states.                                              |
| `updateFilter`         | `WRITE` | Edit a saved filter in place by id (any type). This is how you change its criteria, name, description, folder, or visibility — calling `saveFilter` again creates a second filter. Everything except the id is optional; `root` replaces the whole tree and is strictly validated. Relay returned `warnings`. |
| `deleteFilter`         | `WRITE` | Delete a saved filter by `filterId` (any type — property, contact, or deal). Returns `true` when a row was deleted. A filter outside your organization (or an unknown id) is rejected with `403 forbidden`.                                                                                                   |

<Warning>
  **Read the tree before you edit part of it**

  `updateFilter` replaces `root` **wholesale**. Editing one condition without
  calling `getFilter` first means re-authoring the tree blind and silently
  dropping every condition you didn't know was there. Read it, change the one
  condition you mean to change, and send the modified tree back.

  Both `saveFilter` and `updateFilter` validate field ids and value shapes
  strictly. Discover fields with `listFilterFieldNames`, fetch the selected
  fields' exact union arms with `listFilterFields(fieldIds: [...])`, and re-read
  the saved tree with `getFilter` after updating.
</Warning>

<Note>
  **Relay filter warnings**

  A successful save or update can return `warnings`. These are not errors: the
  filter was persisted, but its criteria may deserve attention — for example,
  selecting same-named counties from different states. Show every warning to
  the user and correct the tree if it reveals an unintended selection.
</Note>

<Note>
  **Cities and counties are identified by id, not by name**

  A `cityFilters` condition takes the `id` from `searchCities` as its `value`
  (with `label` set to `"Name, ST"`, e.g. `"Memphis, TN"`), and a
  `countyFilters` condition takes the 5-digit `fips` from `searchCounties`.
  `saveFilter` and `updateFilter` **reject a bare city or county name**: 11,347
  US city names occur in more than one state, and a county name compiles to a
  `county_fips` term that would match nothing. Resolve the name to an id first.
</Note>

### Tags and lists (`READ` + `WRITE` scopes)

| operationId           | Scope   | What it does                                                                                                       |
| --------------------- | ------- | ------------------------------------------------------------------------------------------------------------------ |
| `searchPropertyTags`  | `READ`  | Search property tags and lists by name. Use a tag id with `addPropertyTags`, a list id with `addPropertiesToList`. |
| `addPropertyTags`     | `WRITE` | Add existing tag(s) (by tag id) to a property.                                                                     |
| `removePropertyTag`   | `WRITE` | Remove one tag (by tag id) from a property.                                                                        |
| `addPropertiesToList` | `WRITE` | Add explicit properties (by id) to list(s).                                                                        |

### Skip tracing (`ADMIN` scope)

| operationId                 | What it does                                                                                                                                                                                                   |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `skipTraceProperty`         | Skip-trace a property to discover its owner + phone numbers/emails. Returns the discovered people inline; re-read them later (free) with `getPropertyOwners`. **Consumes one skip-trace credit (real money).** |
| `manualSkiptrace`           | Skip-trace an explicitly-provided owner + mailing address. **Consumes one skip-trace credit.**                                                                                                                 |
| `createContactFromProperty` | Create a CRM contact from a property. **Triggers skip-trace enrichment — consumes one skip-trace credit.**                                                                                                     |

<Warning>
  **Credit-spending operations**

  Skip-trace operations spend your organization's credits, so they require the
  `ADMIN` scope and the key owner must currently be a team admin. For
  high-volume server-to-server skip tracing there is also the standalone
  [Skip Trace API](/skip-trace-api).
</Warning>

<Note>
  **Properties are global, not org-owned**

  Unlike deals or contacts, a property isn't owned by any one organization — it's
  shared reference data. So property operations are **not** org-guarded on the
  property id: any valid property id (esId) is readable, and referencing one never
  returns `403 forbidden`. Your **scope** (`READ` / `WRITE` / `ADMIN`) still gates
  what you can do. The **tags and lists** you organize properties with *are* yours,
  though — a tag or list id from another org returns `403 forbidden`. Saved filters
  you create are tied to your organization by the key. See
  [Authorization](/developer-api/authorization) for the model.
</Note>

## Example

Run a saved filter and page through the matches:

```bash theme={null}
curl -X POST https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer gsk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "operationId": "listPropertyFilters", "variables": {} }'

curl -X POST https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer gsk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "operationId": "filterProperties", "variables": { "filterId": "FILTER_ID", "limit": 50, "offset": 0 } }'
```

Full variable schemas, response shapes, and worked examples for every
operation are available from the
[discovery endpoint](/developer-api/overview#discovering-operations).
