Topolo Docs Topolo Platform
Open workspace

List prospect contacts

Find active prospect contacts and continue a filtered search without guessing identifiers.

Outcome

Find active prospect contacts and continue a filtered search without guessing identifiers.

Before you start

  • Verify the environment, credential, authorized organization and the published action permission workspace:read.
  • Discover an accessible Engage workspace and bind resourceType=workspace and its resourceId separately from action input. Fixture identifiers grant no access.

Discover the target

  • Select an authorized Engage workspace separately from action input. Start without cursor; select listId from lists.list when restricting membership.
  • For CLI/MCP, pass filter as a structured object. Direct HTTP GET encodes that object as a JSON query value.
topolo whoami --json
topolo actions get app_topolo_engage.contacts.list --json
topolo workspaces list topolo-engage --json

Input fields

FieldRequiredMeaning and constraints
listIdNoOptional discovered list identifier, trimmed non-empty string up to 128 characters; restricts contacts to its memberships.
qNoOptional trimmed search text up to 200 characters; matches email, first name, last name and company.
cursorNoOptional opaque continuation up to 512 characters, returned as nextCursor. Keep the original filters and workspace; omit for the first page.
filterNoOptional strict ICP object. Conditions are ANDed; at most 25 values per array field and 60 values overall. Supported fields include title/seniority, company/domain/country, address/verification/source, custom equality, date ranges, list membership, contactability and latest qualification fit/score. Use the current input schema for exact enums and nested bounds.

Validate, plan and execute

Set ENGAGE_WORKSPACE_ID to the identifier of your selected workspace. Prepare payload.json from the current input schema and discovered identifiers. Use the same payload for validation, planning and execution.

: "${ENGAGE_WORKSPACE_ID:?Set ENGAGE_WORKSPACE_ID to your selected workspace identifier}"
topolo actions validate app_topolo_engage.contacts.list --data @payload.json --json
topolo actions plan app_topolo_engage.contacts.list --resource-type workspace --resource-id "$ENGAGE_WORKSPACE_ID" --data @payload.json --json

Execute the unchanged validated read in the selected workspace.

: "${ENGAGE_WORKSPACE_ID:?Set ENGAGE_WORKSPACE_ID to your selected workspace identifier}"
topolo actions call app_topolo_engage.contacts.list --resource-type workspace --resource-id "$ENGAGE_WORKSPACE_ID" --data @payload.json --json

For MCP, use topolo_get_action, topolo_validate_action, topolo_plan_action and topolo_call_action. Pass the selected resource context separately; confirm:true is required for mutations.

Worked requests and responses

Captured contacts.list · HTTP 200

Action input

{
  "filter": {
    "seniority": [
      "c_level",
      "vp"
    ]
  }
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_3",
      "email": "cy@globex.com",
      "domain": "globex.com",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Globex",
      "title": "VP Marketing",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "CTO",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: ICP filters over the published actions > contacts.list filter > filters by ICP fields over GET, backward compatible without one. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "filter": {
    "contactability": "suppressed"
  }
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_2",
      "email": "bob@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "Sales Manager",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: ICP filters over the published actions > contacts.list filter > filters by contactability with the ledger rule. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "q": "analyt"
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": "Ada",
      "lastName": null,
      "company": "Analytical",
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {
        "tier": "a"
      },
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: audience routes > contacts > creates, reads, searches, edits and archives a manual contact. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{}

Actual local response

{
  "contacts": [
    {
      "id": "contact_9",
      "email": "p08@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_8",
      "email": "p07@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_7",
      "email": "p06@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_6",
      "email": "p05@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_51",
      "email": "p50@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_50",
      "email": "p49@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_5",
      "email": "p04@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_49",
      "email": "p48@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_48",
      "email": "p47@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_47",
      "email": "p46@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_46",
      "email": "p45@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_45",
      "email": "p44@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_44",
      "email": "p43@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_43",
      "email": "p42@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_42",
      "email": "p41@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_41",
      "email": "p40@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_40",
      "email": "p39@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_4",
      "email": "p03@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_39",
      "email": "p38@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_38",
      "email": "p37@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_37",
      "email": "p36@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_36",
      "email": "p35@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_35",
      "email": "p34@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_34",
      "email": "p33@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_33",
      "email": "p32@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_32",
      "email": "p31@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_31",
      "email": "p30@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_30",
      "email": "p29@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_3",
      "email": "p02@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_29",
      "email": "p28@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_28",
      "email": "p27@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_27",
      "email": "p26@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_26",
      "email": "p25@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_25",
      "email": "p24@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_24",
      "email": "p23@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_23",
      "email": "p22@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_22",
      "email": "p21@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_21",
      "email": "p20@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_20",
      "email": "p19@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_2",
      "email": "p01@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_19",
      "email": "p18@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_18",
      "email": "p17@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_17",
      "email": "p16@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_16",
      "email": "p15@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_15",
      "email": "p14@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_14",
      "email": "p13@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_13",
      "email": "p12@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_12",
      "email": "p11@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_11",
      "email": "p10@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_10",
      "email": "p09@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": "WyIyMDI2LTEwLTAxVDAwOjAwOjAwLjAwMFoiLCJjb250YWN0XzEwIl0"
}

Source test: audience routes > contacts > pages newest first with an opaque cursor. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{}

Actual local response

{
  "contacts": [],
  "nextCursor": null
}

Source test: audience routes > permissions > allows reads with workspace:read and refuses writes without workspace:write. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "filter": {
    "titleNone": [
      "sales"
    ],
    "companyIn": [
      "acme"
    ]
  }
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "CTO",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: ICP filters over the published actions > contacts.list filter > filters by ICP fields over GET, backward compatible without one. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{}

Actual local response

{
  "contacts": [
    {
      "id": "contact_3",
      "email": "cy@globex.com",
      "domain": "globex.com",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Globex",
      "title": "VP Marketing",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_2",
      "email": "bob@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "Sales Manager",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "CTO",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: ICP filters over the published actions > contacts.list filter > filters by ICP fields over GET, backward compatible without one. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "filter": {
    "contactability": "eligible"
  }
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_3",
      "email": "cy@globex.com",
      "domain": "globex.com",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Globex",
      "title": "VP Marketing",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "CTO",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: ICP filters over the published actions > contacts.list filter > filters by contactability with the ledger rule. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "q": ""
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": "Ada",
      "lastName": null,
      "company": "Analytical",
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {
        "tier": "a"
      },
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: audience routes > contacts > creates, reads, searches, edits and archives a manual contact. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "q": "nobody"
}

Actual local response

{
  "contacts": [],
  "nextCursor": null
}

Source test: audience routes > contacts > creates, reads, searches, edits and archives a manual contact. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "cursor": "WyIyMDI2LTEwLTAxVDAwOjAwOjAwLjAwMFoiLCJjb250YWN0XzEwIl0"
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_1",
      "email": "p00@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: audience routes > contacts > pages newest first with an opaque cursor. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "listId": "list_1"
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_2",
      "email": "grace@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: audience routes > lists > adds and removes members, counting only active contacts. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "listId": "list_1"
}

Actual local response

{
  "contacts": [],
  "nextCursor": null
}

Source test: audience routes > lists > keeps lists and memberships inside their workspace. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "listId": "list_1"
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_3",
      "email": "grace@navy.mil",
      "domain": "navy.mil",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": "Grace",
      "lastName": null,
      "company": "Navy",
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "csv",
      "custom": {
        "industry": "Defense"
      },
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_2",
      "email": "sales@acme.io",
      "domain": "acme.io",
      "addressType": "role",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Example Co",
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "csv",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": "Ada",
      "lastName": null,
      "company": "Analytical",
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "csv",
      "custom": {
        "industry": "Computing"
      },
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: audience routes > imports > applies idempotently: the same key returns the same result and writes nothing twice. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "q": "ada"
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": null,
      "title": null,
      "website": null,
      "country": null,
      "timezone": null,
      "source": "csv",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: audience routes > imports > applies without a list and honours an explicit mapping that ignores columns. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 200

Action input

{
  "listId": "list_1"
}

Actual local response

{
  "contacts": [
    {
      "id": "contact_2",
      "email": "bob@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "Sales Manager",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    },
    {
      "id": "contact_1",
      "email": "ada@acme.io",
      "domain": "acme.io",
      "addressType": "person",
      "verificationStatus": "unknown",
      "firstName": null,
      "lastName": null,
      "company": "Acme",
      "title": "CTO",
      "website": null,
      "country": null,
      "timezone": null,
      "source": "manual",
      "custom": {},
      "createdAt": "2026-10-01T00:00:00.000Z",
      "updatedAt": "2026-10-01T00:00:00.000Z",
      "archivedAt": null
    }
  ],
  "nextCursor": null
}

Source test: ICP filters over the published actions > lists.members.add_from_filter > adds matching contacts idempotently, reports truncation and audits. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Effects and response meaning

  • Reads at most 50 active contacts ordered by createdAt descending, then id descending. Archived contacts are omitted. Optional q searches email, first name, last name and company; the ICP filter combines all supplied conditions.
  • Follow the exact nextCursor with the same q, listId and filter until it is null. Contactability filtering scans at most 1,000 candidate rows per request, so a short or empty page with nextCursor is not the end of the search. This is a live keyset search, not a snapshot export.
  • The read does not enroll prospects, approve outreach or send messages. Returned classification and verification state do not authorize sending.

Verify the result

  • Retain contacts[].id for contacts.get in the same workspace. Check nextCursor explicitly, rather than using page length as the completion test.
  • Compare each returned contact against your intended search and inspect archivedAt and verificationStatus before a separately approved workflow.

Recover

Retry this read after a transient failure with the same verified workspace and validated input. Rediscover missing identifiers within that workspace; never create or modify a record to make a read succeed.

Refused responses

Captured contacts.list · HTTP 422

Refused input; do not execute

{
  "filter": "{oops"
}

Actual local response

{
  "error": {
    "code": "invalid_action_input",
    "message": "Input for contacts.list is invalid.",
    "details": [
      {
        "expected": "object",
        "code": "invalid_type",
        "path": [
          "filter"
        ],
        "message": "Invalid input: expected object, received string"
      }
    ]
  }
}

Source test: ICP filters over the published actions > contacts.list filter > filters by ICP fields over GET, backward compatible without one. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 503

Action input

{}

Actual local response

{
  "error": {
    "code": "address_hashing_unconfigured",
    "message": "Contact storage is unavailable: the address hashing secret is not configured."
  }
}

Source test: audience routes > fails closed with 503 when the address hashing secret is missing. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 422

Action input

{
  "filter": {
    "titleAny": [
      "v0",
      "v1",
      "v2",
      "v3",
      "v4",
      "v5",
      "v6",
      "v7",
      "v8",
      "v9",
      "v10",
      "v11",
      "v12",
      "v13",
      "v14",
      "v15",
      "v16",
      "v17",
      "v18",
      "v19",
      "v20",
      "v21",
      "v22",
      "v23",
      "v24"
    ],
    "companyIn": [
      "v0",
      "v1",
      "v2",
      "v3",
      "v4",
      "v5",
      "v6",
      "v7",
      "v8",
      "v9",
      "v10",
      "v11",
      "v12",
      "v13",
      "v14",
      "v15",
      "v16",
      "v17",
      "v18",
      "v19",
      "v20",
      "v21",
      "v22",
      "v23",
      "v24"
    ],
    "countryIn": [
      "v0",
      "v1",
      "v2",
      "v3",
      "v4",
      "v5",
      "v6",
      "v7",
      "v8",
      "v9",
      "v10",
      "v11",
      "v12",
      "v13",
      "v14",
      "v15",
      "v16",
      "v17",
      "v18",
      "v19",
      "v20",
      "v21",
      "v22",
      "v23",
      "v24"
    ]
  }
}

Actual local response

{
  "error": {
    "code": "filter_too_complex",
    "message": "A filter may bind at most 60 values; this one binds 75."
  }
}

Source test: ICP filters over the published actions > contacts.list filter > refuses a filter that binds too many values. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 422

Action input

{
  "cursor": "bogus"
}

Actual local response

{
  "error": {
    "code": "invalid_cursor",
    "message": "The cursor is not one this API issued."
  }
}

Source test: audience routes > contacts > returns 422 for an invalid email and for input the contract refuses. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 403

Action input

{}

Actual local response

{
  "error": "workspace_forbidden"
}

Source test: audience routes > permissions > denies a workspace the caller holds no grant for. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured contacts.list · HTTP 422

Refused input; do not execute

{
  "filter": {
    "nope": 1
  }
}

Actual local response

{
  "error": {
    "code": "invalid_action_input",
    "message": "Input for contacts.list is invalid.",
    "details": [
      {
        "code": "unrecognized_keys",
        "keys": [
          "nope"
        ],
        "path": [
          "filter"
        ],
        "message": "Unrecognized key: \"nope\""
      }
    ]
  }
}

Source test: ICP filters over the published actions > contacts.list filter > filters by ICP fields over GET, backward compatible without one. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Error recovery

  • HTTP 403 permission_denied: Stop and inspect the permission required by this action in the current credential. Do not broaden permissions or switch organization automatically.
  • HTTP 422 invalid_action_input: Correct the request against the current input schema and validate it again before planning.
  • HTTP 503 address_hashing_unconfigured: Stop and report the missing address-hashing configuration to the application operator. This read cannot provision it; do not switch context or modify credentials to bypass the refusal.
  • HTTP 422 filter_too_complex: Reduce filter values to the documented per-field and overall bounds, then validate the unchanged intended search again.
  • HTTP 422 invalid_cursor: Discard the malformed or stale cursor and restart the same search. Use only the exact nextCursor returned by that query; never construct or edit one.
  • HTTP 403 workspace_forbidden: Discover an accessible Engage workspace with the current credential and bind that resource explicitly; do not retry the denied fixture identifier.

Evidence and limits

  • contracts/audience.mjs

  • contracts/audience-filter.mjs

  • apps/api/src/audience/audience-routes.ts

  • apps/api/src/audience/contacts-handlers.ts

  • apps/api/src/audience/contact-search.ts

  • apps/api/src/audience/contacts-repository.ts

  • apps/api/src/audience/lists-handlers.ts

  • apps/api/src/audience/lists-repository.ts

  • apps/api/src/audience/filter-source.ts

  • apps/api/test/audience-routes.test.ts

  • apps/api/test/segments-routes.test.ts

  • Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

  • Widget/bootstrap use actual app handler but mocked worker runtime and app identity.

  • No gateway execution, live permissions, external delivery or deployed proof.

The examples are local route captures with synthetic context and simulated providers. They do not prove live authorization, CLI/MCP gateway execution, production state or delivery.