# updateContact

Update a contact by contactId: the general-purpose per-contact write. All of it, contactId too, is one `input` variable the docs cannot expand, so this list is the contract. Identity: `name`, `isArchived` (false RESTORES one archived contact; unarchiveContacts for many), `importantNote` (the record's important-note field, not a timeline note: addContactNote writes those, changeNotePinned pins one). Channels: addPhoneNumbers (verificationStatus: UNVERIFIED unless the person was reached on it) / updatePhoneNumbers / removePhoneNumbers (updatePhoneNumbers sets only verificationStatus, phoneType, note, ranking: a new number is remove-then-add; a US number is stored as 10 digits and formatted for display, so reformatting needs no write), addEmails / updateEmails / removeEmails, addMailingAddresses / updateMailingAddresses / removeMailingAddresses (their home or mailing address: "lives at X, not Y" replaces it here, never as a property; an edit is remove-then-add; removeMailingAddresses takes the MAPPING-row id from mailingAddresses[].id, not an address id). Subject properties: addProperties / updateProperties / removeProperties, how "add 123 Oak St to this contact" is done; addProperties takes a propertyId from findProperties/getProperty plus a verificationStatus. Relatives: `subContacts` (upsert; omit the id to create) and removeSubContacts. Custom fields: updateCustomFieldValues, each { contactId, customFieldId, exactly ONE of textValue / numberValue / dateValue / dropdownSelectedValues per the field type (getContact shows the per-type read-back); dropdownSelectedValues takes the option LABELS (an option id is read as its label), and a value the field has no option for is refused with the field options listed }; the response echoes `customFields` so you can confirm the value landed. Files: deleteFileIds (detaches by UploadedFile id). Tags, lists, teammates, teams: addTagIds/removeTagIds, addToListIds/removeFromListIds, addCollaborators/removeCollaborators, addUserGroupIds/removeUserGroupIds. Synchronous; returns the contact. Omitted fields are untouched; each add*/remove* pair is a delta, not a replacement. For MANY contacts use the bulk ops (addContactTags/removeContactTags, addContactsToList/removeContactsFromList, assignContact/unassignContact, archiveContacts/unarchiveContacts), which are async and return a bulkTaskId.

- Call: `POST https://server.goliathdata.com/api/v1/call` with `{ "operationId": "updateContact", "variables": {...} }`
- Scope: `WRITE`
- Type: mutation
- Idempotency: honors `Idempotency-Key` (24 h)
- Rate-limited: no

## Variables

- `input`: `UpdateContactInput!` (required)
  - `contactId`: `String!` (required)
  - `addProperties`: `[CreateContactPropertyInput!]`
    - `propertyId`: `String!` (required)
    - `propertyString`: `String`
    - `address`: `AddressInput`
      - `id`: `String`
      - `line1`: `String!` (required)
      - `line2`: `String`
      - `city`: `String!` (required)
      - `state`: `String!` (required)
      - `zip`: `String!` (required)
    - `verificationStatus`: `VerificationStatus!` (required, one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `status`: `String`
    - `ranking`: `Int`
  - `updateProperties`: `[UpdateContactPropertyInput!]`
    - `id`: `String!` (required)
    - `verificationStatus`: `VerificationStatus` (one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `status`: `String`
    - `ranking`: `Int`
  - `removeProperties`: `[String!]`
  - `addMailingAddresses`: `[CreateContactMailingAddressInput!]`
    - `addressString`: `String!` (required). Raw single-line address; resolved via MailingAddressResolutionService (property → address → raw).
    - `propertyElasticsearchId`: `ID`. Instant-duplicate case: the property (Property.id / esId) the user copied this mailing address from: e.g. "use my subject property as the mailing address". When set, the mailing row links straight to that property (no ES search).
    - `verificationStatus`: `VerificationStatus` (one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `ranking`: `Int`. Display order; lower is higher (0 = primary).
  - `updateMailingAddresses`: `[UpdateContactMailingAddressInput!]`. Update an existing mailing row's verification / ordering by its mapping-row id (ContactMailingAddress.id). The address text is immutable: edit = remove + re-add.
    - `id`: `ID!` (required)
    - `verificationStatus`: `VerificationStatus` (one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `ranking`: `Int`
  - `removeMailingAddresses`: `[String!]`
  - `isArchived`: `Boolean`
  - `name`: `String`
  - `addCollaborators`: `[ContactCollaboratorInput!]`
    - `userId`: `String!` (required)
    - `role`: `ContactToUserMappingStatus!` (required, one of `REVOKED`, `POINT_PERSON`, `PARTICIPANT`)
    - `createTask`: `CreateTaskInput`
      - `title`: `String!` (required)
      - `taskType`: `String`
      - `timezone`: `Timezone!` (required, one of `IDLW`, `SST`, `HST`, `AKST`, `PST`, `MST`, `AZ`, `CST`, `EST`, `AST`, `BRT`, `FNT`, `AZOT`, `UTC`, `CET`, `EET`, `MSK`, `GST`, `PKT`, `BST`, `ICT`, `JST`, `AEST`, `NCT`, `NZST`). AZ: Arizona: MST all year, no DST.
      - `description`: `String`
      - `endDate`: `DateTime!` (required)
      - `participants`: `[String!]`
      - `contactId`: `String!` (required)
      - `pipelineItemIds`: `[ID!]`. Deals to explicitly attach to the task (creates DealTask join rows). May be empty or omitted.
      - `dealIds`: `[ID!]`
      - `autoCompleteOnNoteAdded`: `Boolean`
      - `autoCompleteOnReassignment`: `Boolean`
      - `createCalendarEvent`: `Boolean`
      - `alongsideOpenTasks`: `Boolean`
  - `removeCollaborators`: `[String!]`
  - `updateCustomFieldValues`: `[UpdateContactCustomFieldInput!]`
    - `contactId`: `String!` (required)
    - `customFieldId`: `String!` (required)
    - `textValue`: `String`
    - `calendarDate`: `String`. Preferred DATE value as a strict calendar day (YYYY-MM-DD). Do not combine with dateValue.
    - `dateValue`: `DateTime`. Legacy DATE compatibility input. Prefer calendarDate for new clients; do not combine both forms.
    - `numberValue`: `Float`
    - `dropdownSelectedValues`: `[String!]`
  - `deleteFileIds`: `[String!]`
  - `importantNote`: `String`
  - `addPhoneNumbers`: `[CreateContactPhoneNumberInput!]`
    - `phoneNumber`: `String!` (required)
    - `verificationStatus`: `VerificationStatus!` (required, one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `phoneType`: `PhoneType` (one of `MOBILE`, `RESIDENTIAL`, `LANDLINE`, `UNKNOWN`)
    - `note`: `String`
    - `ranking`: `Int`
  - `updatePhoneNumbers`: `[UpdateContactPhoneNumberInput!]`
    - `id`: `String!` (required)
    - `verificationStatus`: `VerificationStatus` (one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `phoneType`: `PhoneType` (one of `MOBILE`, `RESIDENTIAL`, `LANDLINE`, `UNKNOWN`)
    - `note`: `String`
    - `ranking`: `Int`
  - `removePhoneNumbers`: `[String!]`
  - `subContacts`: `[SubContactMutationInput!]`
    - `id`: `String`
    - `contactId`: `String!` (required)
    - `name`: `String!` (required)
    - `relation`: `String`
    - `note`: `String`
    - `phoneNumbers`: `[CreateContactPhoneNumberInput!]`
      - `phoneNumber`: `String!` (required)
      - `verificationStatus`: `VerificationStatus!` (required, one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
      - `phoneType`: `PhoneType` (one of `MOBILE`, `RESIDENTIAL`, `LANDLINE`, `UNKNOWN`)
      - `note`: `String`
      - `ranking`: `Int`
    - `emails`: `[CreateContactEmailInput!]`
      - `email`: `String!` (required)
      - `verificationStatus`: `VerificationStatus!` (required, one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
      - `note`: `String`
      - `ranking`: `Int`
  - `removeSubContacts`: `[String!]`
  - `addEmails`: `[CreateContactEmailInput!]`
    - `email`: `String!` (required)
    - `verificationStatus`: `VerificationStatus!` (required, one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `note`: `String`
    - `ranking`: `Int`
  - `updateEmails`: `[UpdateContactEmailInput!]`
    - `id`: `String!` (required)
    - `verificationStatus`: `VerificationStatus` (one of `VERIFIED`, `UNVERIFIED`, `WRONG`)
    - `note`: `String`
    - `ranking`: `Int`
  - `removeEmails`: `[String!]`
  - `addToListIds`: `[ID!]`
  - `removeFromListIds`: `[ID!]`
  - `addTagIds`: `[ID!]`
  - `removeTagIds`: `[ID!]`
  - `addUserGroupIds`: `[ID!]`
  - `removeUserGroupIds`: `[ID!]`

## Response (data, an example)

```json
{
  "contactMutation": {
    "updateContact": {
      "id": "<ID>",
      "name": "…",
      "isArchived": true,
      "emails": [
        {
          "id": "<ID>",
          "email": "…",
          "verificationStatus": "VERIFIED"
        }
      ],
      "phoneNumbers": [
        {
          "id": "<ID>",
          "phoneNumber": "…",
          "phoneType": "MOBILE",
          "verificationStatus": "VERIFIED"
        }
      ],
      "tags": [
        {
          "id": "<ID>",
          "name": "…"
        }
      ],
      "lists": [
        {
          "id": "<ID>",
          "name": "…"
        }
      ],
      "participants": [
        {
          "status": "REVOKED",
          "user": {
            "id": "<ID>",
            "firstName": "…",
            "lastName": "…",
            "email": "…"
          }
        }
      ],
      "userGroups": [
        {
          "id": "<ID>",
          "name": "…"
        }
      ],
      "customFields": [
        {
          "id": "<ID>",
          "name": "…",
          "type": "DROPDOWN",
          "allowMultiple": true,
          "values": {
            "textValue": "…",
            "dateValue": "2026-01-01T00:00:00.000Z",
            "numberValue": 0,
            "dropdownSelectedValues": [
              "…"
            ]
          }
        }
      ]
    }
  }
}
```

## Example

```bash
curl https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer $GOLIATH_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{
    "operationId": "updateContact",
    "variables": {
      "input": {
        "contactId": "<String>"
      }
    }
  }'
```
