Skip to the documentation

Searches

What a client needs, in structure or in their words, versioned as you change it. Served at `/api/v1/searches`. The old `/api/v1/briefs` paths still answer, and say they are old.

List searches

GET/api/v1/searches

Your searches, each at its latest revision, newest saved first. Archived searches stay out unless you ask. Pages by cursor, 20 at a time and up to 50.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:read
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
statusQuery"active" | "archived" | "all"Optionalactive (the default), archived or all. It stays on the next page's link.
limitQueryintegerOptionalHow many to return: 1 to 50, 20 when absent. A number outside that range is clamped; text is ignored.
cursorQuerystringOptionalWhere the last page ended: the cursor inside the previous page's links.next. Pass links as given; a cursor you edit is refused.

Examples

curl "https://liviamatch.com/api/v1/searches" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

200

One page of searches.

One search
{
  "data": [
    {
      "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "version": 1,
      "title": "Okafors, East Nashville",
      "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
      "source": "homes-for-sale",
      "tenure": "buy",
      "budget": {
        "value": 750000,
        "fixed": false,
        "buffer": 10
      },
      "beds": {
        "value": 3,
        "fixed": true,
        "buffer": 0
      },
      "baths": {
        "value": 2,
        "fixed": true,
        "buffer": 0
      },
      "propertyType": "House",
      "timeline": "Exploring",
      "areas": [
        "Nashville"
      ],
      "commutes": [
        {
          "id": "commute-1",
          "label": "Vanderbilt University Medical Center",
          "coords": {
            "lat": 36.1421,
            "lng": -86.8016
          },
          "maxMin": 25
        }
      ],
      "areaPins": [],
      "mustHaves": [
        "Fenced yard",
        "Walkable to coffee"
      ],
      "niceToHaves": [
        "Home office"
      ],
      "details": null,
      "likedHomes": {
        "urls": [],
        "importance": "nice"
      },
      "feel": {
        "text": "",
        "tags": [],
        "importance": "nice"
      },
      "inferred": null,
      "archivedAt": null,
      "updatedAt": "2026-10-06T13:58:20.310Z",
      "links": {
        "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
        "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches",
        "runs": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/runs"
      }
    }
  ],
  "links": {
    "next": null
  }
}
Fields (75)
FieldTypeDescription
dataobject[]
data[].idstring (uuid)
data[].versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data[].titlestring
data[].clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data[].sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data[].tenure"buy" | "rent"
data[].budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data[].budget.valuenumberThe target.
data[].budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data[].budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data[].bedsobjectThe fewest bedrooms.
data[].beds.valuenumberThe target.
data[].beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data[].beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data[].bathsobjectThe fewest bathrooms.
data[].baths.valuenumberThe target.
data[].baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data[].baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data[].propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data[].timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data[].areasstring[]The cities to look in.
data[].commutesobject[]
data[].commutes[].idstring1 to 64 characters
data[].commutes[].labelstringat most 200 characters
data[].commutes[].coordsobject | null
data[].commutes[].coords.latnumber
data[].commutes[].coords.lngnumber
data[].commutes[].maxMininteger0 to 60
data[].commutes[].kind"place" | "any", optional
data[].commutes[].querystring, optional1 to 80 characters
data[].areaPinsobject[]
data[].areaPins[].idstring1 to 64 characters
data[].areaPins[].latnumber
data[].areaPins[].lngnumber
data[].mustHavesstring[]
data[].niceToHavesstring[]
data[].detailsobject | nullAdvanced criteria, or null when none were set.
data[].details.textstringat most 4000 characters, default ""
data[].details.textMode"prefer" | "require"default "prefer"
data[].details.numericobjectdefault {}
data[].details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data[].details.citiesstring[]at most 100 items, default []
data[].details.postalCodesstring[]at most 100 items, default []
data[].details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data[].details.requiredFeaturesstring[]at most 50 items, default []
data[].details.preferredFeaturesstring[]at most 50 items, default []
data[].details.excludedFeaturesstring[]at most 50 items, default []
data[].details.imageDescriptionstringat most 2000 characters, default ""
data[].details.imageTagsstring[]at most 50 items, default []
data[].details.radiusobject, optional
data[].details.radius.latitudenumber-90 to 90
data[].details.radius.longitudenumber-180 to 180
data[].details.radius.kmnumberat most 2000
data[].details.areaobjectdefault {}
data[].details.maxEvidenceAgeDaysintegerat most 3650, default 365
data[].details.missingData"exclude-required" | "penalize"default "exclude-required"
data[].likedHomesobject
data[].likedHomes.urlsstring (uri)[]at most 4 items, default []
data[].likedHomes.importance"nice" | "must"default "nice"
data[].feelobject
data[].feel.textstringat most 2000 characters, default ""
data[].feel.tagsstring[]at most 12 items, default []
data[].feel.importance"nice" | "must"default "nice"
data[].inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data[].inferred.fieldsstring[]at most 40 items
data[].inferred.assumedstring[]at most 10 items
data[].archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data[].updatedAtstring (date-time)When this revision was saved.
data[].linksobject
data[].links.selfstring
data[].links.matchesstringThe old path of runs, which still answers.
data[].links.runsstringWhere to POST to run the search ("Search now"), and GET to list its runs.
linksobject
links.nextstring | nullThe URL of the next page, or null when this is the last. Follow it as given.

Errors

StatusCodeWhen
400invalidThe status is not active, archived or all.
400invalid-cursorThe cursor is not one a page linked to.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Make a search

POST/api/v1/searches

Makes a search from structure and answers 201 with it, its ETag and a Location. The server picks the id.

Budget, beds and baths are required, so a search is never made of starting values. Everything else has an honest default: no preference, an empty list. To start from words, draft one and send what it returned.

A POST that times out may or may not have landed. To make a retry safe, choose the id yourself and use PUT /api/v1/searches/{searchId}: the same id with the same words lands once.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Request body

The whole search. Unknown fields are refused, so a typo fails loudly.

Fields (64)
FieldTypeRequiredDescription
titlestringRequiredWhat you call this brief: 1 to 120 characters.1 to 120 characters
clientIdstring (uuid) | nullOptionalThe client it is for, or null for a brief that is nobody's yet. Attach a client later by saving the brief again.default null
sourcestring | nullOptionalWhat to match against: homes-for-sale, or the source of one of your data sets (GET /api/v1/data-sets). Left out, it starts on the same source a new brief in the app does. Null means none yet, and the brief cannot run.1 to 100 characters
tenure"buy" | "rent"OptionalWhether the client is buying or renting. For rent, budget is a monthly rent.default "buy"
budgetobjectRequiredThe most the client will pay: a price, or a monthly rent. Flexible by 10 percent unless you say otherwise.
budget.valuenumberRequiredat most 100000000
budget.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default false
budget.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 10
bedsobjectRequiredThe fewest bedrooms. Firm unless you say otherwise.
beds.valueintegerRequired0 to 30
beds.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
beds.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
bathsobjectRequiredThe fewest bathrooms. Firm unless you say otherwise.
baths.valuenumberRequired0 to 30
baths.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
baths.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"Optionaldefault "Any"
timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"Optionaldefault "Exploring"
areasstring[]OptionalThe cities to look in. With none, Homes for sale looks around the organization's market, else Nashville, TN.at most 20 items, default []
commutesobject[]OptionalUp to three places the client travels to. A data set cannot time travel, so a search with a commute cannot run against one.at most 3 items, default []
commutes[].idstringOptionalYour own id for this stop, or leave it out and one is made.1 to 64 characters
commutes[].labelstringRequired1 to 200 characters
commutes[].coordsobject | nullRequiredWhere the stop is. Null when kind is any: the match finds the places.
commutes[].coords.latnumberRequired-90 to 90
commutes[].coords.lngnumberRequired-180 to 180
commutes[].maxMinintegerRequiredThe longest drive the client will take, in minutes. 0 means no ceiling.0 to 60
commutes[].kind"place" | "any"Optionalany is a brand, such as Starbucks, rather than one address. Leave it out for one place.
commutes[].querystringOptionalThe brand, when kind is any.1 to 80 characters
areaPinsobject[]OptionalPins on the map that widen where to look. Not drive ceilings.at most 4 items, default []
areaPins[].idstringOptionalYour own id for this pin, or leave it out and one is made.1 to 64 characters
areaPins[].latnumberRequired-90 to 90
areaPins[].lngnumberRequired-180 to 180
mustHavesstring[]Optionalat most 20 items, default []
niceToHavesstring[]Optionalat most 20 items, default []
detailsobject | nullOptionalAdvanced criteria: ranges (square feet, lot, HOA, days on market, and more), features to avoid, keywords, each with its importance. What POST /searches/draft writes when the words name one.
details.textstringOptionalat most 4000 characters, default ""
details.textMode"prefer" | "require"Optionaldefault "prefer"
details.numericobjectOptionaldefault {}
details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]Optionalat most 7 items, default []
details.citiesstring[]Optionalat most 100 items, default []
details.postalCodesstring[]Optionalat most 100 items, default []
details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]Optionalat least 1 items, default ["Active"]
details.requiredFeaturesstring[]Optionalat most 50 items, default []
details.preferredFeaturesstring[]Optionalat most 50 items, default []
details.excludedFeaturesstring[]Optionalat most 50 items, default []
details.imageDescriptionstringOptionalat most 2000 characters, default ""
details.imageTagsstring[]Optionalat most 50 items, default []
details.radiusobjectOptional
details.radius.latitudenumberRequired-90 to 90
details.radius.longitudenumberRequired-180 to 180
details.radius.kmnumberRequiredat most 2000
details.areaobjectOptionaldefault {}
details.maxEvidenceAgeDaysintegerOptionalat most 3650, default 365
details.missingData"exclude-required" | "penalize"Optionaldefault "exclude-required"
likedHomesobjectOptionalLinks to homes the client liked, and how much they matter.default {"urls":[],"importance":"nice"}
likedHomes.urlsstring (uri)[]Optionalat most 4 items, default []
likedHomes.importance"nice" | "must"Optionaldefault "nice"
feelobjectOptionalHow the home should feel, in words and tags, and how much it matters.default {"text":"","tags":[],"importance":"nice"}
feel.textstringOptionalat most 2000 characters, default ""
feel.tagsstring[]Optionalat most 12 items, default []
feel.importance"nice" | "must"Optionaldefault "nice"
inferredobject | nullOptionalWhat was read from words and what was assumed. Pass back what POST /searches/draft returned so the assumptions stay named.
inferred.fieldsstring[]Requiredat most 40 items
inferred.assumedstring[]Requiredat most 10 items
Examples
{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 750000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}

Examples

curl -X POST "https://liviamatch.com/api/v1/searches" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 750000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}'

Responses

201

The search was made, at revision 1.

HeadersETagLocation

A new search
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 1,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 750000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T13:58:20.310Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches",
      "runs": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/runs"
    }
  }
}
Fields (73)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringThe old path of runs, which still answers.
data.links.runsstringWhere to POST to run the search ("Search now"), and GET to list its runs.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
422unknown-clientclientId is not a client in your workspace.
422source-unavailablesource is not Homes for sale and not an active data set of yours (GET /api/v1/data-sets).

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Draft a search from words

POST/api/v1/searches/draft

Reads notes about a client (a consultation, an email, a dictation) and answers the search they describe, in the shape POST /api/v1/searches takes. It saves nothing: look at it, change what is wrong, then send it.

search.inferred (brief.inferred on the old path) names what the words said (fields) and the essentials they never mentioned (assumed). Those are budget and propertyType, each left at the value a new search starts with. A search drafted before 2026-10-22 may also list beds and baths. Beds and baths the words never named are now drafted with no floor (value 0). A field that claims nothing, like that or timeline at Exploring, is not an assumption and is never listed. Pass inferred back when you save, so the assumptions stay named on the search, and set the assumed essentials yourself when you know them.

The words go to the model under the no-retention routing rule, pass the Fair Housing scrub before and after, and are never stored or logged. A draft counts against an hourly cap, and words that name nothing a search can use are refused rather than drafted from starting values.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Request body

The notes to read, and the client they are about when there is one.

Fields (2)
FieldTypeRequiredDescription
textstringRequiredWhat the agent heard or wrote about the client: a consultation, an email, notes. Up to 10,000 characters. It goes to the model under the no-retention routing rule and is never stored.1 to 10000 characters
clientIdstring (uuid) | nullOptionalThe client it is for, or null. It rides on the draft so it can be saved as it is.default null
Examples
{
  "text": "Amara and her husband are moving from Boston in January with two kids and a dog. Budget is around $750k, three bedrooms at least, two baths, somewhere in Nashville near Vanderbilt hospital. A fenced yard is a must, and a home office would be nice.",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28"
}

Examples

curl -X POST "https://liviamatch.com/api/v1/searches/draft" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Amara and her husband are moving from Boston in January with two kids and a dog. Budget is around $750k, three bedrooms at least, two baths, somewhere in Nashville near Vanderbilt hospital. A fenced yard is a must, and a home office would be nice.",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28"
}'

Responses

200

A draft, ready to look at and save.

A draft
{
  "data": {
    "brief": {
      "title": "Boston family, near Vanderbilt",
      "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
      "source": "homes-for-sale",
      "tenure": "buy",
      "budget": {
        "value": 750000,
        "fixed": false,
        "buffer": 10
      },
      "beds": {
        "value": 3,
        "fixed": true,
        "buffer": 0
      },
      "baths": {
        "value": 2,
        "fixed": true,
        "buffer": 0
      },
      "propertyType": "House",
      "timeline": "Exploring",
      "areas": [
        "Nashville"
      ],
      "commutes": [],
      "areaPins": [],
      "mustHaves": [
        "Fenced yard"
      ],
      "niceToHaves": [
        "Home office"
      ],
      "likedHomes": {
        "urls": [],
        "importance": "nice"
      },
      "feel": {
        "text": "",
        "tags": [],
        "importance": "nice"
      },
      "inferred": {
        "fields": [
          "title",
          "budget",
          "beds",
          "baths",
          "cities",
          "feature"
        ],
        "assumed": [
          "propertyType"
        ]
      }
    },
    "search": {
      "title": "Boston family, near Vanderbilt",
      "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
      "source": "homes-for-sale",
      "tenure": "buy",
      "budget": {
        "value": 750000,
        "fixed": false,
        "buffer": 10
      },
      "beds": {
        "value": 3,
        "fixed": true,
        "buffer": 0
      },
      "baths": {
        "value": 2,
        "fixed": true,
        "buffer": 0
      },
      "propertyType": "House",
      "timeline": "Exploring",
      "areas": [
        "Nashville"
      ],
      "commutes": [],
      "areaPins": [],
      "mustHaves": [
        "Fenced yard"
      ],
      "niceToHaves": [
        "Home office"
      ],
      "likedHomes": {
        "urls": [],
        "importance": "nice"
      },
      "feel": {
        "text": "",
        "tags": [],
        "importance": "nice"
      },
      "inferred": {
        "fields": [
          "title",
          "budget",
          "beds",
          "baths",
          "cities",
          "feature"
        ],
        "assumed": [
          "propertyType"
        ]
      }
    },
    "setAside": []
  }
}
Fields (132)
FieldTypeDescription
dataobject
data.briefobjectThe old name for search, with the same body.
data.brief.titlestringWhat you call this brief: 1 to 120 characters.1 to 120 characters
data.brief.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet. Attach a client later by saving the brief again.default null
data.brief.sourcestring | null, optionalWhat to match against: homes-for-sale, or the source of one of your data sets (GET /api/v1/data-sets). Left out, it starts on the same source a new brief in the app does. Null means none yet, and the brief cannot run.1 to 100 characters
data.brief.tenure"buy" | "rent"Whether the client is buying or renting. For rent, budget is a monthly rent.default "buy"
data.brief.budgetobjectThe most the client will pay: a price, or a monthly rent. Flexible by 10 percent unless you say otherwise.
data.brief.budget.valuenumberat most 100000000
data.brief.budget.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default false
data.brief.budget.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 10
data.brief.bedsobjectThe fewest bedrooms. Firm unless you say otherwise.
data.brief.beds.valueinteger0 to 30
data.brief.beds.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
data.brief.beds.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
data.brief.bathsobjectThe fewest bathrooms. Firm unless you say otherwise.
data.brief.baths.valuenumber0 to 30
data.brief.baths.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
data.brief.baths.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
data.brief.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"default "Any"
data.brief.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"default "Exploring"
data.brief.areasstring[]The cities to look in. With none, Homes for sale looks around the organization's market, else Nashville, TN.at most 20 items, default []
data.brief.commutesobject[]Up to three places the client travels to. A data set cannot time travel, so a search with a commute cannot run against one.at most 3 items, default []
data.brief.commutes[].idstring, optionalYour own id for this stop, or leave it out and one is made.1 to 64 characters
data.brief.commutes[].labelstring1 to 200 characters
data.brief.commutes[].coordsobject | nullWhere the stop is. Null when kind is any: the match finds the places.
data.brief.commutes[].coords.latnumber-90 to 90
data.brief.commutes[].coords.lngnumber-180 to 180
data.brief.commutes[].maxMinintegerThe longest drive the client will take, in minutes. 0 means no ceiling.0 to 60
data.brief.commutes[].kind"place" | "any", optionalany is a brand, such as Starbucks, rather than one address. Leave it out for one place.
data.brief.commutes[].querystring, optionalThe brand, when kind is any.1 to 80 characters
data.brief.areaPinsobject[]Pins on the map that widen where to look. Not drive ceilings.at most 4 items, default []
data.brief.areaPins[].idstring, optionalYour own id for this pin, or leave it out and one is made.1 to 64 characters
data.brief.areaPins[].latnumber-90 to 90
data.brief.areaPins[].lngnumber-180 to 180
data.brief.mustHavesstring[]at most 20 items, default []
data.brief.niceToHavesstring[]at most 20 items, default []
data.brief.detailsobject | null, optionalAdvanced criteria: ranges (square feet, lot, HOA, days on market, and more), features to avoid, keywords, each with its importance. What POST /searches/draft writes when the words name one.
data.brief.details.textstringat most 4000 characters, default ""
data.brief.details.textMode"prefer" | "require"default "prefer"
data.brief.details.numericobjectdefault {}
data.brief.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.brief.details.citiesstring[]at most 100 items, default []
data.brief.details.postalCodesstring[]at most 100 items, default []
data.brief.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.brief.details.requiredFeaturesstring[]at most 50 items, default []
data.brief.details.preferredFeaturesstring[]at most 50 items, default []
data.brief.details.excludedFeaturesstring[]at most 50 items, default []
data.brief.details.imageDescriptionstringat most 2000 characters, default ""
data.brief.details.imageTagsstring[]at most 50 items, default []
data.brief.details.radiusobject, optional
data.brief.details.radius.latitudenumber-90 to 90
data.brief.details.radius.longitudenumber-180 to 180
data.brief.details.radius.kmnumberat most 2000
data.brief.details.areaobjectdefault {}
data.brief.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.brief.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.brief.likedHomesobjectLinks to homes the client liked, and how much they matter.default {"urls":[],"importance":"nice"}
data.brief.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.brief.likedHomes.importance"nice" | "must"default "nice"
data.brief.feelobjectHow the home should feel, in words and tags, and how much it matters.default {"text":"","tags":[],"importance":"nice"}
data.brief.feel.textstringat most 2000 characters, default ""
data.brief.feel.tagsstring[]at most 12 items, default []
data.brief.feel.importance"nice" | "must"default "nice"
data.brief.inferredobject | null, optionalWhat was read from words and what was assumed. Pass back what POST /searches/draft returned so the assumptions stay named.
data.brief.inferred.fieldsstring[]at most 40 items
data.brief.inferred.assumedstring[]at most 10 items
data.searchobjectThe search the words describe, in the shape POST /api/v1/searches takes. inferred says what was read and what was assumed.
data.search.titlestringWhat you call this brief: 1 to 120 characters.1 to 120 characters
data.search.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet. Attach a client later by saving the brief again.default null
data.search.sourcestring | null, optionalWhat to match against: homes-for-sale, or the source of one of your data sets (GET /api/v1/data-sets). Left out, it starts on the same source a new brief in the app does. Null means none yet, and the brief cannot run.1 to 100 characters
data.search.tenure"buy" | "rent"Whether the client is buying or renting. For rent, budget is a monthly rent.default "buy"
data.search.budgetobjectThe most the client will pay: a price, or a monthly rent. Flexible by 10 percent unless you say otherwise.
data.search.budget.valuenumberat most 100000000
data.search.budget.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default false
data.search.budget.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 10
data.search.bedsobjectThe fewest bedrooms. Firm unless you say otherwise.
data.search.beds.valueinteger0 to 30
data.search.beds.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
data.search.beds.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
data.search.bathsobjectThe fewest bathrooms. Firm unless you say otherwise.
data.search.baths.valuenumber0 to 30
data.search.baths.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
data.search.baths.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
data.search.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"default "Any"
data.search.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"default "Exploring"
data.search.areasstring[]The cities to look in. With none, Homes for sale looks around the organization's market, else Nashville, TN.at most 20 items, default []
data.search.commutesobject[]Up to three places the client travels to. A data set cannot time travel, so a search with a commute cannot run against one.at most 3 items, default []
data.search.commutes[].idstring, optionalYour own id for this stop, or leave it out and one is made.1 to 64 characters
data.search.commutes[].labelstring1 to 200 characters
data.search.commutes[].coordsobject | nullWhere the stop is. Null when kind is any: the match finds the places.
data.search.commutes[].coords.latnumber-90 to 90
data.search.commutes[].coords.lngnumber-180 to 180
data.search.commutes[].maxMinintegerThe longest drive the client will take, in minutes. 0 means no ceiling.0 to 60
data.search.commutes[].kind"place" | "any", optionalany is a brand, such as Starbucks, rather than one address. Leave it out for one place.
data.search.commutes[].querystring, optionalThe brand, when kind is any.1 to 80 characters
data.search.areaPinsobject[]Pins on the map that widen where to look. Not drive ceilings.at most 4 items, default []
data.search.areaPins[].idstring, optionalYour own id for this pin, or leave it out and one is made.1 to 64 characters
data.search.areaPins[].latnumber-90 to 90
data.search.areaPins[].lngnumber-180 to 180
data.search.mustHavesstring[]at most 20 items, default []
data.search.niceToHavesstring[]at most 20 items, default []
data.search.detailsobject | null, optionalAdvanced criteria: ranges (square feet, lot, HOA, days on market, and more), features to avoid, keywords, each with its importance. What POST /searches/draft writes when the words name one.
data.search.details.textstringat most 4000 characters, default ""
data.search.details.textMode"prefer" | "require"default "prefer"
data.search.details.numericobjectdefault {}
data.search.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.search.details.citiesstring[]at most 100 items, default []
data.search.details.postalCodesstring[]at most 100 items, default []
data.search.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.search.details.requiredFeaturesstring[]at most 50 items, default []
data.search.details.preferredFeaturesstring[]at most 50 items, default []
data.search.details.excludedFeaturesstring[]at most 50 items, default []
data.search.details.imageDescriptionstringat most 2000 characters, default ""
data.search.details.imageTagsstring[]at most 50 items, default []
data.search.details.radiusobject, optional
data.search.details.radius.latitudenumber-90 to 90
data.search.details.radius.longitudenumber-180 to 180
data.search.details.radius.kmnumberat most 2000
data.search.details.areaobjectdefault {}
data.search.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.search.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.search.likedHomesobjectLinks to homes the client liked, and how much they matter.default {"urls":[],"importance":"nice"}
data.search.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.search.likedHomes.importance"nice" | "must"default "nice"
data.search.feelobjectHow the home should feel, in words and tags, and how much it matters.default {"text":"","tags":[],"importance":"nice"}
data.search.feel.textstringat most 2000 characters, default ""
data.search.feel.tagsstring[]at most 12 items, default []
data.search.feel.importance"nice" | "must"default "nice"
data.search.inferredobject | null, optionalWhat was read from words and what was assumed. Pass back what POST /searches/draft returned so the assumptions stay named.
data.search.inferred.fieldsstring[]at most 40 items
data.search.inferred.assumedstring[]at most 10 items
data.setAsidestring[]The kinds of phrase Fair Housing rules kept out of the draft, by class and never by their words.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
422unknown-clientclientId is not a client in your workspace.
422draft-emptyThe words name nothing a search can use.
429rate-limitedThe hour's draft cap is spent; Retry-After says when it lifts.
502ai-failedThe model failed or answered out of shape. Nothing was drafted.
503ai-unavailableNo model is configured on this deployment.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 monthly-cap-reached500 internal

Read a search

GET/api/v1/searches/{searchId}

One of your searches at its latest revision. The ETag is the revision; send it back as If-Match to change the search without overwriting a change you have not seen.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:read
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
searchIdPathstring (uuid)RequiredThe search's id.

Examples

curl "https://liviamatch.com/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

200

The search.

HeadersETag

A search
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 1,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 750000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T13:58:20.310Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches",
      "runs": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/runs"
    }
  }
}
Fields (73)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringThe old path of runs, which still answers.
data.links.runsstringWhere to POST to run the search ("Search now"), and GET to list its runs.

Errors

StatusCodeWhen
404not-foundNo such search in your workspace.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Save a search at an id

PUT/api/v1/searches/{searchId}

Saves a search at an id you choose, which makes a retry land once: 201 when the id is new, 200 when it names one of your searches, and 409 when it belongs to someone else's, which is never touched. A change is saved as a new revision, as the app's editor saves it, and the matches already made keep the revision they ran. Saving what the latest revision already says writes nothing and answers 200.

Send If-Match with the ETag you last read to be sure you are not overwriting someone else's change; a stale version is 412 and nothing is written. What you leave out takes its default, so send the whole search: a source you leave out keeps the search's own.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
searchIdPathstring (uuid)RequiredThe search's id.
If-MatchHeaderstringOptionalThe ETag of the revision you read, such as "2". If the search has changed since, nothing is written and the answer is 412.

Request body

The whole search, as for making one.

Fields (64)
FieldTypeRequiredDescription
titlestringRequiredWhat you call this brief: 1 to 120 characters.1 to 120 characters
clientIdstring (uuid) | nullOptionalThe client it is for, or null for a brief that is nobody's yet. Attach a client later by saving the brief again.default null
sourcestring | nullOptionalWhat to match against: homes-for-sale, or the source of one of your data sets (GET /api/v1/data-sets). Left out, it starts on the same source a new brief in the app does. Null means none yet, and the brief cannot run.1 to 100 characters
tenure"buy" | "rent"OptionalWhether the client is buying or renting. For rent, budget is a monthly rent.default "buy"
budgetobjectRequiredThe most the client will pay: a price, or a monthly rent. Flexible by 10 percent unless you say otherwise.
budget.valuenumberRequiredat most 100000000
budget.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default false
budget.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 10
bedsobjectRequiredThe fewest bedrooms. Firm unless you say otherwise.
beds.valueintegerRequired0 to 30
beds.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
beds.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
bathsobjectRequiredThe fewest bathrooms. Firm unless you say otherwise.
baths.valuenumberRequired0 to 30
baths.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
baths.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"Optionaldefault "Any"
timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"Optionaldefault "Exploring"
areasstring[]OptionalThe cities to look in. With none, Homes for sale looks around the organization's market, else Nashville, TN.at most 20 items, default []
commutesobject[]OptionalUp to three places the client travels to. A data set cannot time travel, so a search with a commute cannot run against one.at most 3 items, default []
commutes[].idstringOptionalYour own id for this stop, or leave it out and one is made.1 to 64 characters
commutes[].labelstringRequired1 to 200 characters
commutes[].coordsobject | nullRequiredWhere the stop is. Null when kind is any: the match finds the places.
commutes[].coords.latnumberRequired-90 to 90
commutes[].coords.lngnumberRequired-180 to 180
commutes[].maxMinintegerRequiredThe longest drive the client will take, in minutes. 0 means no ceiling.0 to 60
commutes[].kind"place" | "any"Optionalany is a brand, such as Starbucks, rather than one address. Leave it out for one place.
commutes[].querystringOptionalThe brand, when kind is any.1 to 80 characters
areaPinsobject[]OptionalPins on the map that widen where to look. Not drive ceilings.at most 4 items, default []
areaPins[].idstringOptionalYour own id for this pin, or leave it out and one is made.1 to 64 characters
areaPins[].latnumberRequired-90 to 90
areaPins[].lngnumberRequired-180 to 180
mustHavesstring[]Optionalat most 20 items, default []
niceToHavesstring[]Optionalat most 20 items, default []
detailsobject | nullOptionalAdvanced criteria: ranges (square feet, lot, HOA, days on market, and more), features to avoid, keywords, each with its importance. What POST /searches/draft writes when the words name one.
details.textstringOptionalat most 4000 characters, default ""
details.textMode"prefer" | "require"Optionaldefault "prefer"
details.numericobjectOptionaldefault {}
details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]Optionalat most 7 items, default []
details.citiesstring[]Optionalat most 100 items, default []
details.postalCodesstring[]Optionalat most 100 items, default []
details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]Optionalat least 1 items, default ["Active"]
details.requiredFeaturesstring[]Optionalat most 50 items, default []
details.preferredFeaturesstring[]Optionalat most 50 items, default []
details.excludedFeaturesstring[]Optionalat most 50 items, default []
details.imageDescriptionstringOptionalat most 2000 characters, default ""
details.imageTagsstring[]Optionalat most 50 items, default []
details.radiusobjectOptional
details.radius.latitudenumberRequired-90 to 90
details.radius.longitudenumberRequired-180 to 180
details.radius.kmnumberRequiredat most 2000
details.areaobjectOptionaldefault {}
details.maxEvidenceAgeDaysintegerOptionalat most 3650, default 365
details.missingData"exclude-required" | "penalize"Optionaldefault "exclude-required"
likedHomesobjectOptionalLinks to homes the client liked, and how much they matter.default {"urls":[],"importance":"nice"}
likedHomes.urlsstring (uri)[]Optionalat most 4 items, default []
likedHomes.importance"nice" | "must"Optionaldefault "nice"
feelobjectOptionalHow the home should feel, in words and tags, and how much it matters.default {"text":"","tags":[],"importance":"nice"}
feel.textstringOptionalat most 2000 characters, default ""
feel.tagsstring[]Optionalat most 12 items, default []
feel.importance"nice" | "must"Optionaldefault "nice"
inferredobject | nullOptionalWhat was read from words and what was assumed. Pass back what POST /searches/draft returned so the assumptions stay named.
inferred.fieldsstring[]Requiredat most 40 items
inferred.assumedstring[]Requiredat most 10 items
Examples
{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 700000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}

Examples

curl -X PUT "https://liviamatch.com/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 700000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}'

Responses

201

A new search was saved at revision 1.

HeadersETagLocation

A new search
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 1,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 750000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T13:58:20.310Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches",
      "runs": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/runs"
    }
  }
}
Fields (73)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringThe old path of runs, which still answers.
data.links.runsstringWhere to POST to run the search ("Search now"), and GET to list its runs.
200

An existing search was saved as a new revision, or already said this.

HeadersETag

Revision 2
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 2,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 700000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T14:40:09.771Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches",
      "runs": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/runs"
    }
  }
}
Fields (73)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringThe old path of runs, which still answers.
data.links.runsstringWhere to POST to run the search ("Search now"), and GET to list its runs.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
400invalid-if-matchThe If-Match is not a revision.
422unknown-clientclientId is not a client in your workspace.
422source-unavailablesource is not Homes for sale and not an active data set of yours (GET /api/v1/data-sets).
409id-unavailableThe id belongs to a search that is not yours.
412revision-mismatchThe search changed since the revision in If-Match.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

List searches

GET/api/v1/briefs

Your searches, each at its latest revision, newest saved first. Archived searches stay out unless you ask. Pages by cursor, 20 at a time and up to 50.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:read
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
statusQuery"active" | "archived" | "all"Optionalactive (the default), archived or all. It stays on the next page's link.
limitQueryintegerOptionalHow many to return: 1 to 50, 20 when absent. A number outside that range is clamped; text is ignored.
cursorQuerystringOptionalWhere the last page ended: the cursor inside the previous page's links.next. Pass links as given; a cursor you edit is refused.

Examples

curl "https://liviamatch.com/api/v1/briefs" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

200

One page of searches.

One search
{
  "data": [
    {
      "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "version": 1,
      "title": "Okafors, East Nashville",
      "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
      "source": "homes-for-sale",
      "tenure": "buy",
      "budget": {
        "value": 750000,
        "fixed": false,
        "buffer": 10
      },
      "beds": {
        "value": 3,
        "fixed": true,
        "buffer": 0
      },
      "baths": {
        "value": 2,
        "fixed": true,
        "buffer": 0
      },
      "propertyType": "House",
      "timeline": "Exploring",
      "areas": [
        "Nashville"
      ],
      "commutes": [
        {
          "id": "commute-1",
          "label": "Vanderbilt University Medical Center",
          "coords": {
            "lat": 36.1421,
            "lng": -86.8016
          },
          "maxMin": 25
        }
      ],
      "areaPins": [],
      "mustHaves": [
        "Fenced yard",
        "Walkable to coffee"
      ],
      "niceToHaves": [
        "Home office"
      ],
      "details": null,
      "likedHomes": {
        "urls": [],
        "importance": "nice"
      },
      "feel": {
        "text": "",
        "tags": [],
        "importance": "nice"
      },
      "inferred": null,
      "archivedAt": null,
      "updatedAt": "2026-10-06T13:58:20.310Z",
      "links": {
        "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
        "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches"
      }
    }
  ],
  "links": {
    "next": null
  }
}
Fields (74)
FieldTypeDescription
dataobject[]
data[].idstring (uuid)
data[].versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data[].titlestring
data[].clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data[].sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data[].tenure"buy" | "rent"
data[].budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data[].budget.valuenumberThe target.
data[].budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data[].budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data[].bedsobjectThe fewest bedrooms.
data[].beds.valuenumberThe target.
data[].beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data[].beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data[].bathsobjectThe fewest bathrooms.
data[].baths.valuenumberThe target.
data[].baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data[].baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data[].propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data[].timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data[].areasstring[]The cities to look in.
data[].commutesobject[]
data[].commutes[].idstring1 to 64 characters
data[].commutes[].labelstringat most 200 characters
data[].commutes[].coordsobject | null
data[].commutes[].coords.latnumber
data[].commutes[].coords.lngnumber
data[].commutes[].maxMininteger0 to 60
data[].commutes[].kind"place" | "any", optional
data[].commutes[].querystring, optional1 to 80 characters
data[].areaPinsobject[]
data[].areaPins[].idstring1 to 64 characters
data[].areaPins[].latnumber
data[].areaPins[].lngnumber
data[].mustHavesstring[]
data[].niceToHavesstring[]
data[].detailsobject | nullAdvanced criteria, or null when none were set.
data[].details.textstringat most 4000 characters, default ""
data[].details.textMode"prefer" | "require"default "prefer"
data[].details.numericobjectdefault {}
data[].details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data[].details.citiesstring[]at most 100 items, default []
data[].details.postalCodesstring[]at most 100 items, default []
data[].details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data[].details.requiredFeaturesstring[]at most 50 items, default []
data[].details.preferredFeaturesstring[]at most 50 items, default []
data[].details.excludedFeaturesstring[]at most 50 items, default []
data[].details.imageDescriptionstringat most 2000 characters, default ""
data[].details.imageTagsstring[]at most 50 items, default []
data[].details.radiusobject, optional
data[].details.radius.latitudenumber-90 to 90
data[].details.radius.longitudenumber-180 to 180
data[].details.radius.kmnumberat most 2000
data[].details.areaobjectdefault {}
data[].details.maxEvidenceAgeDaysintegerat most 3650, default 365
data[].details.missingData"exclude-required" | "penalize"default "exclude-required"
data[].likedHomesobject
data[].likedHomes.urlsstring (uri)[]at most 4 items, default []
data[].likedHomes.importance"nice" | "must"default "nice"
data[].feelobject
data[].feel.textstringat most 2000 characters, default ""
data[].feel.tagsstring[]at most 12 items, default []
data[].feel.importance"nice" | "must"default "nice"
data[].inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data[].inferred.fieldsstring[]at most 40 items
data[].inferred.assumedstring[]at most 10 items
data[].archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data[].updatedAtstring (date-time)When this revision was saved.
data[].linksobject
data[].links.selfstring
data[].links.matchesstringWhere to POST to start a match, and GET to list this brief's matches.
linksobject
links.nextstring | nullThe URL of the next page, or null when this is the last. Follow it as given.

Errors

StatusCodeWhen
400invalidThe status is not active, archived or all.
400invalid-cursorThe cursor is not one a page linked to.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Make a search

POST/api/v1/briefs

Makes a search from structure and answers 201 with it, its ETag and a Location. The server picks the id.

Budget, beds and baths are required, so a search is never made of starting values. Everything else has an honest default: no preference, an empty list. To start from words, draft one and send what it returned.

A POST that times out may or may not have landed. To make a retry safe, choose the id yourself and use PUT /api/v1/searches/{searchId}: the same id with the same words lands once.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Request body

The whole search. Unknown fields are refused, so a typo fails loudly.

Fields (64)
FieldTypeRequiredDescription
titlestringRequiredWhat you call this brief: 1 to 120 characters.1 to 120 characters
clientIdstring (uuid) | nullOptionalThe client it is for, or null for a brief that is nobody's yet. Attach a client later by saving the brief again.default null
sourcestring | nullOptionalWhat to match against: homes-for-sale, or the source of one of your data sets (GET /api/v1/data-sets). Left out, it starts on the same source a new brief in the app does. Null means none yet, and the brief cannot run.1 to 100 characters
tenure"buy" | "rent"OptionalWhether the client is buying or renting. For rent, budget is a monthly rent.default "buy"
budgetobjectRequiredThe most the client will pay: a price, or a monthly rent. Flexible by 10 percent unless you say otherwise.
budget.valuenumberRequiredat most 100000000
budget.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default false
budget.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 10
bedsobjectRequiredThe fewest bedrooms. Firm unless you say otherwise.
beds.valueintegerRequired0 to 30
beds.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
beds.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
bathsobjectRequiredThe fewest bathrooms. Firm unless you say otherwise.
baths.valuenumberRequired0 to 30
baths.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
baths.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"Optionaldefault "Any"
timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"Optionaldefault "Exploring"
areasstring[]OptionalThe cities to look in. With none, Homes for sale looks around the organization's market, else Nashville, TN.at most 20 items, default []
commutesobject[]OptionalUp to three places the client travels to. A data set cannot time travel, so a search with a commute cannot run against one.at most 3 items, default []
commutes[].idstringOptionalYour own id for this stop, or leave it out and one is made.1 to 64 characters
commutes[].labelstringRequired1 to 200 characters
commutes[].coordsobject | nullRequiredWhere the stop is. Null when kind is any: the match finds the places.
commutes[].coords.latnumberRequired-90 to 90
commutes[].coords.lngnumberRequired-180 to 180
commutes[].maxMinintegerRequiredThe longest drive the client will take, in minutes. 0 means no ceiling.0 to 60
commutes[].kind"place" | "any"Optionalany is a brand, such as Starbucks, rather than one address. Leave it out for one place.
commutes[].querystringOptionalThe brand, when kind is any.1 to 80 characters
areaPinsobject[]OptionalPins on the map that widen where to look. Not drive ceilings.at most 4 items, default []
areaPins[].idstringOptionalYour own id for this pin, or leave it out and one is made.1 to 64 characters
areaPins[].latnumberRequired-90 to 90
areaPins[].lngnumberRequired-180 to 180
mustHavesstring[]Optionalat most 20 items, default []
niceToHavesstring[]Optionalat most 20 items, default []
detailsobject | nullOptionalAdvanced criteria: ranges (square feet, lot, HOA, days on market, and more), features to avoid, keywords, each with its importance. What POST /searches/draft writes when the words name one.
details.textstringOptionalat most 4000 characters, default ""
details.textMode"prefer" | "require"Optionaldefault "prefer"
details.numericobjectOptionaldefault {}
details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]Optionalat most 7 items, default []
details.citiesstring[]Optionalat most 100 items, default []
details.postalCodesstring[]Optionalat most 100 items, default []
details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]Optionalat least 1 items, default ["Active"]
details.requiredFeaturesstring[]Optionalat most 50 items, default []
details.preferredFeaturesstring[]Optionalat most 50 items, default []
details.excludedFeaturesstring[]Optionalat most 50 items, default []
details.imageDescriptionstringOptionalat most 2000 characters, default ""
details.imageTagsstring[]Optionalat most 50 items, default []
details.radiusobjectOptional
details.radius.latitudenumberRequired-90 to 90
details.radius.longitudenumberRequired-180 to 180
details.radius.kmnumberRequiredat most 2000
details.areaobjectOptionaldefault {}
details.maxEvidenceAgeDaysintegerOptionalat most 3650, default 365
details.missingData"exclude-required" | "penalize"Optionaldefault "exclude-required"
likedHomesobjectOptionalLinks to homes the client liked, and how much they matter.default {"urls":[],"importance":"nice"}
likedHomes.urlsstring (uri)[]Optionalat most 4 items, default []
likedHomes.importance"nice" | "must"Optionaldefault "nice"
feelobjectOptionalHow the home should feel, in words and tags, and how much it matters.default {"text":"","tags":[],"importance":"nice"}
feel.textstringOptionalat most 2000 characters, default ""
feel.tagsstring[]Optionalat most 12 items, default []
feel.importance"nice" | "must"Optionaldefault "nice"
inferredobject | nullOptionalWhat was read from words and what was assumed. Pass back what POST /searches/draft returned so the assumptions stay named.
inferred.fieldsstring[]Requiredat most 40 items
inferred.assumedstring[]Requiredat most 10 items
Examples
{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 750000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}

Examples

curl -X POST "https://liviamatch.com/api/v1/briefs" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 750000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}'

Responses

201

The search was made, at revision 1.

HeadersETagLocation

A new search
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 1,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 750000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T13:58:20.310Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches"
    }
  }
}
Fields (72)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringWhere to POST to start a match, and GET to list this brief's matches.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
422unknown-clientclientId is not a client in your workspace.
422source-unavailablesource is not Homes for sale and not an active data set of yours (GET /api/v1/data-sets).

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Draft a search from words

POST/api/v1/briefs/draft

Reads notes about a client (a consultation, an email, a dictation) and answers the search they describe, in the shape POST /api/v1/searches takes. It saves nothing: look at it, change what is wrong, then send it.

search.inferred (brief.inferred on the old path) names what the words said (fields) and the essentials they never mentioned (assumed). Those are budget and propertyType, each left at the value a new search starts with. A search drafted before 2026-10-22 may also list beds and baths. Beds and baths the words never named are now drafted with no floor (value 0). A field that claims nothing, like that or timeline at Exploring, is not an assumption and is never listed. Pass inferred back when you save, so the assumptions stay named on the search, and set the assumed essentials yourself when you know them.

The words go to the model under the no-retention routing rule, pass the Fair Housing scrub before and after, and are never stored or logged. A draft counts against an hourly cap, and words that name nothing a search can use are refused rather than drafted from starting values.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Request body

The notes to read, and the client they are about when there is one.

Fields (2)
FieldTypeRequiredDescription
textstringRequiredWhat the agent heard or wrote about the client: a consultation, an email, notes. Up to 10,000 characters. It goes to the model under the no-retention routing rule and is never stored.1 to 10000 characters
clientIdstring (uuid) | nullOptionalThe client it is for, or null. It rides on the draft so it can be saved as it is.default null
Examples
{
  "text": "Amara and her husband are moving from Boston in January with two kids and a dog. Budget is around $750k, three bedrooms at least, two baths, somewhere in Nashville near Vanderbilt hospital. A fenced yard is a must, and a home office would be nice.",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28"
}

Examples

curl -X POST "https://liviamatch.com/api/v1/briefs/draft" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "text": "Amara and her husband are moving from Boston in January with two kids and a dog. Budget is around $750k, three bedrooms at least, two baths, somewhere in Nashville near Vanderbilt hospital. A fenced yard is a must, and a home office would be nice.",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28"
}'

Responses

200

A draft, ready to look at and save.

A draft
{
  "data": {
    "brief": {
      "title": "Boston family, near Vanderbilt",
      "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
      "source": "homes-for-sale",
      "tenure": "buy",
      "budget": {
        "value": 750000,
        "fixed": false,
        "buffer": 10
      },
      "beds": {
        "value": 3,
        "fixed": true,
        "buffer": 0
      },
      "baths": {
        "value": 2,
        "fixed": true,
        "buffer": 0
      },
      "propertyType": "House",
      "timeline": "Exploring",
      "areas": [
        "Nashville"
      ],
      "commutes": [],
      "areaPins": [],
      "mustHaves": [
        "Fenced yard"
      ],
      "niceToHaves": [
        "Home office"
      ],
      "likedHomes": {
        "urls": [],
        "importance": "nice"
      },
      "feel": {
        "text": "",
        "tags": [],
        "importance": "nice"
      },
      "inferred": {
        "fields": [
          "title",
          "budget",
          "beds",
          "baths",
          "cities",
          "feature"
        ],
        "assumed": [
          "propertyType"
        ]
      }
    },
    "setAside": []
  }
}
Fields (67)
FieldTypeDescription
dataobject
data.briefobjectThe search the words describe, in the shape POST /api/v1/searches takes. inferred says what was read and what was assumed.
data.brief.titlestringWhat you call this brief: 1 to 120 characters.1 to 120 characters
data.brief.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet. Attach a client later by saving the brief again.default null
data.brief.sourcestring | null, optionalWhat to match against: homes-for-sale, or the source of one of your data sets (GET /api/v1/data-sets). Left out, it starts on the same source a new brief in the app does. Null means none yet, and the brief cannot run.1 to 100 characters
data.brief.tenure"buy" | "rent"Whether the client is buying or renting. For rent, budget is a monthly rent.default "buy"
data.brief.budgetobjectThe most the client will pay: a price, or a monthly rent. Flexible by 10 percent unless you say otherwise.
data.brief.budget.valuenumberat most 100000000
data.brief.budget.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default false
data.brief.budget.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 10
data.brief.bedsobjectThe fewest bedrooms. Firm unless you say otherwise.
data.brief.beds.valueinteger0 to 30
data.brief.beds.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
data.brief.beds.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
data.brief.bathsobjectThe fewest bathrooms. Firm unless you say otherwise.
data.brief.baths.valuenumber0 to 30
data.brief.baths.fixedbooleantrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
data.brief.baths.buffernumberHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
data.brief.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"default "Any"
data.brief.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"default "Exploring"
data.brief.areasstring[]The cities to look in. With none, Homes for sale looks around the organization's market, else Nashville, TN.at most 20 items, default []
data.brief.commutesobject[]Up to three places the client travels to. A data set cannot time travel, so a search with a commute cannot run against one.at most 3 items, default []
data.brief.commutes[].idstring, optionalYour own id for this stop, or leave it out and one is made.1 to 64 characters
data.brief.commutes[].labelstring1 to 200 characters
data.brief.commutes[].coordsobject | nullWhere the stop is. Null when kind is any: the match finds the places.
data.brief.commutes[].coords.latnumber-90 to 90
data.brief.commutes[].coords.lngnumber-180 to 180
data.brief.commutes[].maxMinintegerThe longest drive the client will take, in minutes. 0 means no ceiling.0 to 60
data.brief.commutes[].kind"place" | "any", optionalany is a brand, such as Starbucks, rather than one address. Leave it out for one place.
data.brief.commutes[].querystring, optionalThe brand, when kind is any.1 to 80 characters
data.brief.areaPinsobject[]Pins on the map that widen where to look. Not drive ceilings.at most 4 items, default []
data.brief.areaPins[].idstring, optionalYour own id for this pin, or leave it out and one is made.1 to 64 characters
data.brief.areaPins[].latnumber-90 to 90
data.brief.areaPins[].lngnumber-180 to 180
data.brief.mustHavesstring[]at most 20 items, default []
data.brief.niceToHavesstring[]at most 20 items, default []
data.brief.detailsobject | null, optionalAdvanced criteria: ranges (square feet, lot, HOA, days on market, and more), features to avoid, keywords, each with its importance. What POST /searches/draft writes when the words name one.
data.brief.details.textstringat most 4000 characters, default ""
data.brief.details.textMode"prefer" | "require"default "prefer"
data.brief.details.numericobjectdefault {}
data.brief.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.brief.details.citiesstring[]at most 100 items, default []
data.brief.details.postalCodesstring[]at most 100 items, default []
data.brief.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.brief.details.requiredFeaturesstring[]at most 50 items, default []
data.brief.details.preferredFeaturesstring[]at most 50 items, default []
data.brief.details.excludedFeaturesstring[]at most 50 items, default []
data.brief.details.imageDescriptionstringat most 2000 characters, default ""
data.brief.details.imageTagsstring[]at most 50 items, default []
data.brief.details.radiusobject, optional
data.brief.details.radius.latitudenumber-90 to 90
data.brief.details.radius.longitudenumber-180 to 180
data.brief.details.radius.kmnumberat most 2000
data.brief.details.areaobjectdefault {}
data.brief.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.brief.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.brief.likedHomesobjectLinks to homes the client liked, and how much they matter.default {"urls":[],"importance":"nice"}
data.brief.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.brief.likedHomes.importance"nice" | "must"default "nice"
data.brief.feelobjectHow the home should feel, in words and tags, and how much it matters.default {"text":"","tags":[],"importance":"nice"}
data.brief.feel.textstringat most 2000 characters, default ""
data.brief.feel.tagsstring[]at most 12 items, default []
data.brief.feel.importance"nice" | "must"default "nice"
data.brief.inferredobject | null, optionalWhat was read from words and what was assumed. Pass back what POST /searches/draft returned so the assumptions stay named.
data.brief.inferred.fieldsstring[]at most 40 items
data.brief.inferred.assumedstring[]at most 10 items
data.setAsidestring[]The kinds of phrase Fair Housing rules kept out of the draft, by class and never by their words.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
422unknown-clientclientId is not a client in your workspace.
422draft-emptyThe words name nothing a search can use.
429rate-limitedThe hour's draft cap is spent; Retry-After says when it lifts.
502ai-failedThe model failed or answered out of shape. Nothing was drafted.
503ai-unavailableNo model is configured on this deployment.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 monthly-cap-reached500 internal

Read a search

GET/api/v1/briefs/{searchId}

One of your searches at its latest revision. The ETag is the revision; send it back as If-Match to change the search without overwriting a change you have not seen.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:read
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
searchIdPathstring (uuid)RequiredThe search's id.

Examples

curl "https://liviamatch.com/api/v1/briefs/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592" \
  -H "Authorization: Bearer $LIVIA_API_KEY"

Responses

200

The search.

HeadersETag

A search
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 1,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 750000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T13:58:20.310Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches"
    }
  }
}
Fields (72)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringWhere to POST to start a match, and GET to list this brief's matches.

Errors

StatusCodeWhen
404not-foundNo such search in your workspace.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal

Save a search at an id

PUT/api/v1/briefs/{searchId}

Saves a search at an id you choose, which makes a retry land once: 201 when the id is new, 200 when it names one of your searches, and 409 when it belongs to someone else's, which is never touched. A change is saved as a new revision, as the app's editor saves it, and the matches already made keep the revision they ran. Saving what the latest revision already says writes nothing and answers 200.

Send If-Match with the ETag you last read to be sure you are not overwriting someone else's change; a stale version is 412 and nothing is written. What you leave out takes its default, so send the whole search: a source you leave out keeps the search's own.

An API key carrying the scope named here, or a signed-in session.

Scope
briefs:write
Key kinds
PersonalOrganization

Required and optional fields, allowed values and errors, as the page shows them.

Parameters

NameInTypeRequiredDescription
searchIdPathstring (uuid)RequiredThe search's id.
If-MatchHeaderstringOptionalThe ETag of the revision you read, such as "2". If the search has changed since, nothing is written and the answer is 412.

Request body

The whole search, as for making one.

Fields (64)
FieldTypeRequiredDescription
titlestringRequiredWhat you call this brief: 1 to 120 characters.1 to 120 characters
clientIdstring (uuid) | nullOptionalThe client it is for, or null for a brief that is nobody's yet. Attach a client later by saving the brief again.default null
sourcestring | nullOptionalWhat to match against: homes-for-sale, or the source of one of your data sets (GET /api/v1/data-sets). Left out, it starts on the same source a new brief in the app does. Null means none yet, and the brief cannot run.1 to 100 characters
tenure"buy" | "rent"OptionalWhether the client is buying or renting. For rent, budget is a monthly rent.default "buy"
budgetobjectRequiredThe most the client will pay: a price, or a monthly rent. Flexible by 10 percent unless you say otherwise.
budget.valuenumberRequiredat most 100000000
budget.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default false
budget.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 10
bedsobjectRequiredThe fewest bedrooms. Firm unless you say otherwise.
beds.valueintegerRequired0 to 30
beds.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
beds.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
bathsobjectRequiredThe fewest bathrooms. Firm unless you say otherwise.
baths.valuenumberRequired0 to 30
baths.fixedbooleanOptionaltrue holds the value exactly. false lets a home miss it by up to buffer percent and still count.default true
baths.buffernumberOptionalHow many percent a home may miss the value by when fixed is false. Ignored when it is true.0 to 50, default 0
propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"Optionaldefault "Any"
timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"Optionaldefault "Exploring"
areasstring[]OptionalThe cities to look in. With none, Homes for sale looks around the organization's market, else Nashville, TN.at most 20 items, default []
commutesobject[]OptionalUp to three places the client travels to. A data set cannot time travel, so a search with a commute cannot run against one.at most 3 items, default []
commutes[].idstringOptionalYour own id for this stop, or leave it out and one is made.1 to 64 characters
commutes[].labelstringRequired1 to 200 characters
commutes[].coordsobject | nullRequiredWhere the stop is. Null when kind is any: the match finds the places.
commutes[].coords.latnumberRequired-90 to 90
commutes[].coords.lngnumberRequired-180 to 180
commutes[].maxMinintegerRequiredThe longest drive the client will take, in minutes. 0 means no ceiling.0 to 60
commutes[].kind"place" | "any"Optionalany is a brand, such as Starbucks, rather than one address. Leave it out for one place.
commutes[].querystringOptionalThe brand, when kind is any.1 to 80 characters
areaPinsobject[]OptionalPins on the map that widen where to look. Not drive ceilings.at most 4 items, default []
areaPins[].idstringOptionalYour own id for this pin, or leave it out and one is made.1 to 64 characters
areaPins[].latnumberRequired-90 to 90
areaPins[].lngnumberRequired-180 to 180
mustHavesstring[]Optionalat most 20 items, default []
niceToHavesstring[]Optionalat most 20 items, default []
detailsobject | nullOptionalAdvanced criteria: ranges (square feet, lot, HOA, days on market, and more), features to avoid, keywords, each with its importance. What POST /searches/draft writes when the words name one.
details.textstringOptionalat most 4000 characters, default ""
details.textMode"prefer" | "require"Optionaldefault "prefer"
details.numericobjectOptionaldefault {}
details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]Optionalat most 7 items, default []
details.citiesstring[]Optionalat most 100 items, default []
details.postalCodesstring[]Optionalat most 100 items, default []
details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]Optionalat least 1 items, default ["Active"]
details.requiredFeaturesstring[]Optionalat most 50 items, default []
details.preferredFeaturesstring[]Optionalat most 50 items, default []
details.excludedFeaturesstring[]Optionalat most 50 items, default []
details.imageDescriptionstringOptionalat most 2000 characters, default ""
details.imageTagsstring[]Optionalat most 50 items, default []
details.radiusobjectOptional
details.radius.latitudenumberRequired-90 to 90
details.radius.longitudenumberRequired-180 to 180
details.radius.kmnumberRequiredat most 2000
details.areaobjectOptionaldefault {}
details.maxEvidenceAgeDaysintegerOptionalat most 3650, default 365
details.missingData"exclude-required" | "penalize"Optionaldefault "exclude-required"
likedHomesobjectOptionalLinks to homes the client liked, and how much they matter.default {"urls":[],"importance":"nice"}
likedHomes.urlsstring (uri)[]Optionalat most 4 items, default []
likedHomes.importance"nice" | "must"Optionaldefault "nice"
feelobjectOptionalHow the home should feel, in words and tags, and how much it matters.default {"text":"","tags":[],"importance":"nice"}
feel.textstringOptionalat most 2000 characters, default ""
feel.tagsstring[]Optionalat most 12 items, default []
feel.importance"nice" | "must"Optionaldefault "nice"
inferredobject | nullOptionalWhat was read from words and what was assumed. Pass back what POST /searches/draft returned so the assumptions stay named.
inferred.fieldsstring[]Requiredat most 40 items
inferred.assumedstring[]Requiredat most 10 items
Examples
{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 700000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}

Examples

curl -X PUT "https://liviamatch.com/api/v1/briefs/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592" \
  -H "Authorization: Bearer $LIVIA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Okafors, East Nashville",
  "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
  "source": "homes-for-sale",
  "budget": {
    "value": 700000
  },
  "beds": {
    "value": 3
  },
  "baths": {
    "value": 2
  },
  "propertyType": "House",
  "areas": [
    "Nashville"
  ],
  "commutes": [
    {
      "label": "Vanderbilt University Medical Center",
      "coords": {
        "lat": 36.1421,
        "lng": -86.8016
      },
      "maxMin": 25
    }
  ],
  "mustHaves": [
    "Fenced yard",
    "Walkable to coffee"
  ],
  "niceToHaves": [
    "Home office"
  ]
}'

Responses

201

A new search was saved at revision 1.

HeadersETagLocation

A new search
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 1,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 750000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T13:58:20.310Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches"
    }
  }
}
Fields (72)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringWhere to POST to start a match, and GET to list this brief's matches.
200

An existing search was saved as a new revision, or already said this.

HeadersETag

Revision 2
{
  "data": {
    "id": "7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
    "version": 2,
    "title": "Okafors, East Nashville",
    "clientId": "9c4e1a73-2b85-4d06-8f1a-7d3b5e9c0a28",
    "source": "homes-for-sale",
    "tenure": "buy",
    "budget": {
      "value": 700000,
      "fixed": false,
      "buffer": 10
    },
    "beds": {
      "value": 3,
      "fixed": true,
      "buffer": 0
    },
    "baths": {
      "value": 2,
      "fixed": true,
      "buffer": 0
    },
    "propertyType": "House",
    "timeline": "Exploring",
    "areas": [
      "Nashville"
    ],
    "commutes": [
      {
        "id": "commute-1",
        "label": "Vanderbilt University Medical Center",
        "coords": {
          "lat": 36.1421,
          "lng": -86.8016
        },
        "maxMin": 25
      }
    ],
    "areaPins": [],
    "mustHaves": [
      "Fenced yard",
      "Walkable to coffee"
    ],
    "niceToHaves": [
      "Home office"
    ],
    "details": null,
    "likedHomes": {
      "urls": [],
      "importance": "nice"
    },
    "feel": {
      "text": "",
      "tags": [],
      "importance": "nice"
    },
    "inferred": null,
    "archivedAt": null,
    "updatedAt": "2026-10-06T14:40:09.771Z",
    "links": {
      "self": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592",
      "matches": "/api/v1/searches/7d2f8a40-b6c1-4e35-9a07-c4e1d8b3f592/matches"
    }
  }
}
Fields (72)
FieldTypeDescription
dataobject
data.idstring (uuid)
data.versionintegerThe revision. It counts up on every save; the same number is the ETag.at least 1
data.titlestring
data.clientIdstring (uuid) | nullThe client it is for, or null for a brief that is nobody's yet.
data.sourcestring | nullWhat it matches against: homes-for-sale, a data set's source, or null when none is chosen yet (the brief cannot run).
data.tenure"buy" | "rent"
data.budgetobjectThe most the client will pay: a price, or a monthly rent for rent.
data.budget.valuenumberThe target.
data.budget.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.budget.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bedsobjectThe fewest bedrooms.
data.beds.valuenumberThe target.
data.beds.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.beds.buffernumberHow many percent a home may miss the value by when fixed is false.
data.bathsobjectThe fewest bathrooms.
data.baths.valuenumberThe target.
data.baths.fixedbooleantrue holds the value exactly; false lets a home miss it by up to buffer percent.
data.baths.buffernumberHow many percent a home may miss the value by when fixed is false.
data.propertyType"Any" | "House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other"
data.timeline"Exploring" | "Within 3 months" | "3–6 months" | "6+ months"
data.areasstring[]The cities to look in.
data.commutesobject[]
data.commutes[].idstring1 to 64 characters
data.commutes[].labelstringat most 200 characters
data.commutes[].coordsobject | null
data.commutes[].coords.latnumber
data.commutes[].coords.lngnumber
data.commutes[].maxMininteger0 to 60
data.commutes[].kind"place" | "any", optional
data.commutes[].querystring, optional1 to 80 characters
data.areaPinsobject[]
data.areaPins[].idstring1 to 64 characters
data.areaPins[].latnumber
data.areaPins[].lngnumber
data.mustHavesstring[]
data.niceToHavesstring[]
data.detailsobject | nullAdvanced criteria, or null when none were set.
data.details.textstringat most 4000 characters, default ""
data.details.textMode"prefer" | "require"default "prefer"
data.details.numericobjectdefault {}
data.details.propertyTypes("House" | "Townhouse" | "Condo" | "Multi-family" | "Land" | "Manufactured" | "Other")[]at most 7 items, default []
data.details.citiesstring[]at most 100 items, default []
data.details.postalCodesstring[]at most 100 items, default []
data.details.statuses("Active" | "Pending" | "Sold" | "Withdrawn")[]at least 1 items, default ["Active"]
data.details.requiredFeaturesstring[]at most 50 items, default []
data.details.preferredFeaturesstring[]at most 50 items, default []
data.details.excludedFeaturesstring[]at most 50 items, default []
data.details.imageDescriptionstringat most 2000 characters, default ""
data.details.imageTagsstring[]at most 50 items, default []
data.details.radiusobject, optional
data.details.radius.latitudenumber-90 to 90
data.details.radius.longitudenumber-180 to 180
data.details.radius.kmnumberat most 2000
data.details.areaobjectdefault {}
data.details.maxEvidenceAgeDaysintegerat most 3650, default 365
data.details.missingData"exclude-required" | "penalize"default "exclude-required"
data.likedHomesobject
data.likedHomes.urlsstring (uri)[]at most 4 items, default []
data.likedHomes.importance"nice" | "must"default "nice"
data.feelobject
data.feel.textstringat most 2000 characters, default ""
data.feel.tagsstring[]at most 12 items, default []
data.feel.importance"nice" | "must"default "nice"
data.inferredobject | nullWhat was read from words and what was assumed, when the brief came from a draft; null otherwise.
data.inferred.fieldsstring[]at most 40 items
data.inferred.assumedstring[]at most 10 items
data.archivedAtstring (date-time) | nullWhen it was archived in the app, or null.
data.updatedAtstring (date-time)When this revision was saved.
data.linksobject
data.links.selfstring
data.links.matchesstringWhere to POST to start a match, and GET to list this brief's matches.

Errors

StatusCodeWhen
400invalidThe body failed validation; issues names each field.
400invalid-jsonThe body is empty or not JSON.
413too-largeThe body is over 64 KiB.
400invalid-if-matchThe If-Match is not a revision.
422unknown-clientclientId is not a client in your workspace.
422source-unavailablesource is not Homes for sale and not an active data set of yours (GET /api/v1/data-sets).
409id-unavailableThe id belongs to a search that is not yours.
412revision-mismatchThe search changed since the revision in If-Match.

Any call of this kind can also answer401 unauthenticated401 invalid-api-key403 insufficient-scope429 rate-limited429 monthly-cap-reached500 internal