# getContact

MERGED IDS RESOLVE: an id merged into another contact returns the SURVIVING record, so the `id` that comes back can differ from the one you sent. Use the returned id from then on, never the old one; it is not an error. A merge chain that leads nowhere answers as not-found. Fetch one contact by id, the full record: identity, emails, phones (with DNC status), mailing addresses, subject properties (`property.id` feeds getRelatedProperties), tags, lists, CUSTOM-FIELD VALUES, teammates + roles, teams, notes (with `isPinned`, `isHidden` and `replies`), linked deals (`isArchived: true` is not live), seller-intent score, enrichment/archive flags. A note is the team's record, never a message from the contact; calls are not here (listContactActivities [CALL]). A note's or reply's `author` { kind: USER | AI, id, name } is who WROTE it; read that, not `createdByUser`, which is null on a note an AI assistant wrote for a teammate. A hidden note or reply is shown only to admins; `replies` also omits ones you may not see (e.g. an outside author's), so a missing reply is not proof it is gone. CUSTOM FIELDS: the ONLY read-back for values written via createContact.addCustomFieldValues / updateContact.updateCustomFieldValues (listContactCustomFields returns definitions, never values). `customFields` is the organization's field catalog, not this contact's answers, listed whether or not the contact has one, so its length says nothing about the contact (fields sharing a normalized name collapse to one entry, so it can differ from listContactCustomFields). The value is in `values`, NULL when this contact has none: null means UNSET, not missing, unreadable or an error. Read the ONE sub-field matching the field `type`; the other three stay null on every type: TEXT and LINK → `values.textValue`; NUMBER and DOLLAR → `values.numberValue` (DOLLAR is a plain number as written, NOT cents); DATE → `values.dateValue` (ISO 8601); DROPDOWN → `values.dropdownSelectedValues`, the selected option LABELS (not option ids), at most one entry unless `allowMultiple` is true. Reading the wrong one reports an unset field for a contact that has an answer. A LINK value is stored normalized (a bare host gains its scheme), so compare what you wrote with what comes back rather than assume byte equality.

- Call: `POST https://server.goliathdata.com/api/v1/call` with `{ "operationId": "getContact", "variables": {...} }`
- Scope: `READ`
- Type: query
- Idempotency: a read; rejects `Idempotency-Key`
- Rate-limited: no

## Variables

- `contactId`: `ID!` (required)

## Response (data, an example)

```json
{
  "contactQuery": {
    "contact": {
      "id": "<ID>",
      "name": "…",
      "createdAt": "2026-01-01T00:00:00.000Z",
      "isArchived": true,
      "isEnriched": true,
      "sellerIntentScore": 0,
      "doNotContact": true,
      "doNotContactReason": "…",
      "doNotContactSetAt": "2026-01-01T00:00:00.000Z",
      "doNotContactSetBy": {
        "id": "<ID>",
        "firstName": "…",
        "lastName": "…"
      },
      "emails": [
        {
          "id": "<ID>",
          "email": "…",
          "verificationStatus": "VERIFIED"
        }
      ],
      "phoneNumbers": [
        {
          "id": "<ID>",
          "phoneNumber": "…",
          "phoneType": "MOBILE",
          "verificationStatus": "VERIFIED",
          "dncStatus": {
            "isDnc": true,
            "isLitigator": true
          }
        }
      ],
      "mailingAddresses": [
        {
          "id": "<ID>",
          "rawText": "…",
          "verificationStatus": "VERIFIED",
          "address": {
            "addressFull": "…"
          }
        }
      ],
      "properties": [
        {
          "id": "<ID>",
          "propertyString": "…",
          "status": "…",
          "verificationStatus": "VERIFIED",
          "property": {
            "id": "<ID>"
          }
        }
      ],
      "tags": [
        {
          "id": "<ID>",
          "name": "…"
        }
      ],
      "lists": [
        {
          "id": "<ID>",
          "name": "…"
        }
      ],
      "customFields": [
        {
          "id": "<ID>",
          "name": "…",
          "type": "DROPDOWN",
          "allowMultiple": true,
          "values": {
            "textValue": "…",
            "dateValue": "2026-01-01T00:00:00.000Z",
            "numberValue": 0,
            "dropdownSelectedValues": [
              "…"
            ]
          }
        }
      ],
      "participants": [
        {
          "status": "REVOKED",
          "user": {
            "id": "<ID>",
            "firstName": "…",
            "lastName": "…",
            "email": "…"
          }
        }
      ],
      "userGroups": [
        {
          "id": "<ID>",
          "name": "…"
        }
      ],
      "notes": [
        {
          "id": "<ID>",
          "body": "…",
          "createdAt": "2026-01-01T00:00:00.000Z",
          "author": {
            "kind": "USER",
            "id": "<ID>",
            "name": "…"
          },
          "createdByUser": {
            "id": "<ID>",
            "firstName": "…",
            "lastName": "…"
          },
          "isPinned": true,
          "isHidden": true,
          "replies": [
            {
              "id": "<ID>",
              "body": "…",
              "isHidden": true,
              "author": {
                "kind": "USER",
                "id": "<ID>",
                "name": "…"
              }
            }
          ]
        }
      ],
      "deals": [
        {
          "id": "<ID>",
          "title": "…",
          "priceCents": "…",
          "isArchived": true,
          "priceFormatted": "…",
          "stage": {
            "id": "<ID>",
            "name": "…"
          }
        }
      ]
    }
  }
}
```

## Example

```bash
curl https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer $GOLIATH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operationId": "getContact",
    "variables": {
      "contactId": "<contactId>"
    }
  }'
```
