GoliathDevelopersGet an API key
Reference/Contactsgenerated from the gateway manifest

listContactActivities

A contact's activity timeline.

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

A contact's activity timeline (calls, texts, emails, notes, system events), most recent first. Filter with activityTypes (e.g. [CALL, TEXT, EMAIL]) and direction (INBOUND/OUTBOUND); page with limit/offset (default 25, max 50). Each entry inlines its call/text/email/note payload: notes and texts in full, calls with their summary, emails with BOTH snippet (a short preview) and textExtract (the FULL plain-text body). Read textExtract, not snippet, whenever the question is whether something appears in the history: a detail past the preview's first lines would wrongly look absent. textExtract is NULL on the ~3% of emails that arrived HTML-only, whose body this op cannot read AT ALL: null means UNREAD, not empty. Never conclude such an email lacks what you look for; say which emails you could not read and send the user to the contact's timeline in the app. On a NOTE entry, the note's own author { kind: USER | AI, id, name } says who wrote it (the entry's createdByUser is null for a note an AI assistant wrote for a teammate). An UPDATED_TASK entry carries metadata.oldValues (title, endDate, timezone, taskType, participants) plus newValues.endDate: THE UNDO PATH for a task edit, the only durable record of a prior value since Task keeps no history. Reverse an edit by writing oldValues back with updateTask; never call a previous value unrecoverable without having looked. Only tasks WITH a contact get one, one per edit, so the oldest holds the pre-change value. The heavier history read: getContact does not include this feed. "Did they call / call back" reads activityTypes [CALL]: texts and notes never answer it. A NOTE is the team's own record, never a message: never quote one as the contact's text or email.

curl https://server.goliathdata.com/api/v1/call \
  -H "Authorization: Bearer $GOLIATH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "operationId": "listContactActivities",
    "variables": {
      "contactId": "<contactId>"
    }
  }'
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.listContactActivities({
  contactId: '<contactId>'
})
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: 'listContactActivities',
    variables: {
      contactId: '<contactId>'
    }
  }),
})
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.

contactIdID!required
limitInt

Default 25.

offsetInt

Default 0.

activityTypes[ActivityType!]
NOTE_CREATEDNOTE_DELETEDNOTE_UPDATEDNOTE_PINNEDNOTE_UNPINNEDUSER_MENTIONED_IN_NOTEREPLY_CREATEDREPLY_DELETEDREPLY_UPDATEDREACTED_TO_REPLYREACTED_TO_NOTEREMOVED_REPLY_REACTIONREMOVED_NOTE_REACTIONASSIGNEDUNASSIGNEDCONTACT_ARCHIVEDCONTACT_UNARCHIVEDADD_COLLABORATORREMOVE_COLLABORATORCALLVOICEMAIL_LEFTTEXTEMAILFILE_ADDEDFILE_REMOVEDCREATED_APPOINTMENTDELETED_APPOINTMENTUPDATED_APPOINTMENTCREATED_TASKDELETED_TASKUPDATED_TASKADDED_PERSON_EMAILDELETED_PERSON_EMAILUPDATED_PERSON_EMAILADDED_PERSON_PHONEDELETED_PERSON_PHONEUPDATED_PERSON_PHONEUPDATED_PIPELINE_ITEM_PRICEUPDATED_DEAL_PRICEUPDATED_SELLER_MOTIVATIONUPDATED_TIME_FRAMECREATED_IMPORTANT_NOTEDELETED_IMPORTANT_NOTEUPDATED_IMPORTANT_NOTEAI_EMPLOYEE_ATTACHEDAI_EMPLOYEE_REMOVEDAI_EMPLOYEE_RANAI_EMPLOYEE_ESCALATEDAI_EMPLOYEE_SCHEDULE_CHANGEDTAG_UPDATEDLIST_UPDATEDCSV_ROW_IMPORTEDDIRECT_MAILEMAIL_OUTREACHCONTRACTSLACKMETA_LEAD_FORM_SUBMITTEDPROPERTY_VISITED
directionActivityDirection
INBOUNDOUTBOUND

Response

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

response shape
{
  "data": {
    "contactQuery": {
      "contact": {
        "id": "<ID>",
        "activities": [
          {
            "id": "<ID>",
            "type": "NOTE_CREATED",
            "createdAt": "2026-01-01T00:00:00.000Z",
            "isFromTeamMember": true,
            "createdByUser": {
              "id": "<ID>",
              "firstName": "…",
              "lastName": "…"
            },
            "note": {
              "id": "<ID>",
              "body": "…",
              "createdAt": "2026-01-01T00:00:00.000Z",
              "author": {
                "kind": "USER",
                "id": "<ID>",
                "name": "…"
              }
            },
            "call": {
              "id": "<ID>",
              "direction": "INBOUND",
              "durationSeconds": 0,
              "status": "RINGING",
              "summary": "…",
              "recordingUrl": "…",
              "disposition": "Connected",
              "dispositionNote": "…",
              "fromPhoneNumber": "…",
              "toPhoneNumber": "…",
              "createdAt": "2026-01-01T00:00:00.000Z"
            },
            "text": {
              "id": "<ID>",
              "message": "…",
              "direction": "INBOUND",
              "fromPhoneNumber": "…",
              "toPhoneNumber": "…",
              "createdAt": "2026-01-01T00:00:00.000Z"
            },
            "email": {
              "id": "<ID>",
              "subject": "…",
              "snippet": "…",
              "textExtract": "…",
              "fromEmail": "…",
              "fromName": "…",
              "toEmails": [
                "…"
              ],
              "direction": "…",
              "internalDate": "2026-01-01T00:00:00.000Z"
            },
            "metadata": {
              "taskId": "…",
              "oldValues": {
                "title": "…",
                "endDate": "…",
                "timezone": "…",
                "taskType": "…",
                "participants": [
                  "…"
                ]
              },
              "newValues": {
                "endDate": "…"
              }
            }
          }
        ]
      }
    }
  }
}

Errors

Behaviour

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