GoliathDevelopersGet an API key
Reference/Contactsgenerated from the gateway manifest

findContacts

Fuzzy-search contacts by name, phone, email, or address.

POST/api/v1/callREADreadruns as the key's owner
View as Markdown

Fuzzy-search contacts by name, phone, email, or address. A phone may be its last four digits ("0142"). ARCHIVED contacts are included, marked isArchived (includeArchived: false drops them): one is still in the workspace, never "not in your contacts"; before a write, ask (a form): restore (unarchiveContacts), write anyway, or skip. Rows are QUALIFYING CANDIDATES, relevance-ranked, not matches: each leg (name, phone, email, address) keeps a row only if it clears a trigram-similarity threshold, and survivors are ranked by match quality, not raw score. So an empty result means nothing cleared the bar, and the top row is "the best that did", not the record you named. One shared word clears it: "Northgate Holdings" with no Northgate returns "McNeil Holdings" as totalCount 1. A single result is not evidence of certainty. Before using a contactId in a WRITE, check personName against the name the user said. If it differs, ask which contact they meant rather than write to the best guess: offer the near match as an ASK_USER_QUESTIONS choice naming that person; if you do write, report the name the write echoes, not the one you searched for (see addContactNote).

curl https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer $GOLIATH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operationId": "findContacts",
    "variables": {
      "searchTerm": "<String>"
    }
  }'
import { GoliathClient } from '@goliath-data/sdk'

const goliath = new GoliathClient({
  apiKey: process.env.GOLIATH_API_KEY!,
  baseUrl: 'https://server.goliathdata.com',
})

const result = await goliath.contacts.findContacts({
  searchTerm: '<String>'
})
const res = await fetch('https://server.goliathdata.com/api/v1/call', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.GOLIATH_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    operationId: 'findContacts',
    variables: {
      searchTerm: '<String>'
    }
  }),
})
const { data, errors } = await res.json()

limit is clamped to 50.

Variables

The example sends only what the schema requires. Some operations also need one of several optional variables (one filter or another, say); the description above says which.

searchTermString!required
limitInt

Default 20.

offsetInt

Default 0.

includeArchivedBoolean

Default true.

Response

What comes back under data: a list shows as one entry, and a value as its type.

response shape
{
  "data": {
    "contactQuery": {
      "getContactIdentityResults": {
        "results": [
          {
            "contactId": "<ID>",
            "personName": "…",
            "propertyAddress": "…",
            "phoneNumber": "…",
            "email": "…",
            "isArchived": true
          }
        ],
        "totalCount": 0,
        "hasMore": true
      }
    }
  }
}

Errors

Behaviour

A read. It rejects an Idempotency-Key header with 400 bad_request.