Topolo Docs Topolo Platform
Open workspace

Create prospect list

Create an empty prospect list without enrolling its contacts.

Outcome

Create an empty prospect list without enrolling its contacts.

Before you start

  • Verify the environment, credential, authorized organization and the published action permission workspace:write.
  • Discover an accessible Engage workspace and bind resourceType=workspace and its resourceId separately from action input. Fixture identifiers grant no access.
  • Approve the exact mutation and its effects before CLI --confirm or MCP confirm:true. This documentation does not authorize outreach.

Discover the target

  • Select the intended workspace. Read lists.list to inspect active lists before approving a new one; equal names do not establish identity.
topolo whoami --json
topolo actions get app_topolo_engage.lists.create --json
topolo workspaces list topolo-engage --json

Input fields

FieldRequiredMeaning and constraints
nameYesTrimmed non-empty list name up to 120 characters; required on create and optional on update. Names are not an idempotency key.
descriptionNoOptional trimmed description up to 2,000 characters. Null or blank becomes null; omitted on update retains the existing description.

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.lists.create --data @payload.json --json
topolo actions plan app_topolo_engage.lists.create --resource-type workspace --resource-id "$ENGAGE_WORKSPACE_ID" --data @payload.json --confirm --json

Review the plan and obtain approval for the exact effects before executing the unchanged request.

: "${ENGAGE_WORKSPACE_ID:?Set ENGAGE_WORKSPACE_ID to your selected workspace identifier}"
topolo actions call app_topolo_engage.lists.create --resource-type workspace --resource-id "$ENGAGE_WORKSPACE_ID" --data @payload.json --confirm --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 lists.create · HTTP 201

Action input

{
  "name": "Founders",
  "description": ""
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Founders",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": 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 lists.create · HTTP 201

Action input

{
  "name": "Imported"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Imported",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": 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 lists.create · HTTP 201

Action input

{
  "name": "L"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "L",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": null
  }
}

Source test: audience routes > imports > updates changed contacts, matches unchanged ones and adds both to the list under a new key. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured lists.create · HTTP 201

Action input

{
  "name": "Gone"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Gone",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": null
  }
}

Source test: audience routes > imports > refuses unusable files, mappings and target lists. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured lists.create · HTTP 201

Action input

{
  "name": "Other"
}

Actual local response

{
  "list": {
    "id": "list_2",
    "name": "Other",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": 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 lists.create · HTTP 201

Action input

{
  "name": "Acme"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Acme",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": 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.

Captured lists.create · HTTP 201

Action input

{
  "name": "Reachable"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Reachable",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": null
  }
}

Source test: ICP filters over the published actions > lists.members.add_from_filter > applies a contactability filter before adding. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured lists.create · HTTP 201

Action input

{
  "name": "Target"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Target",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T09:00:00.000Z",
    "updatedAt": "2026-10-01T09:00:00.000Z",
    "archivedAt": null
  }
}

Source test: sourcing workflows over the published actions > creates, lists, gets, updates and deletes a workflow with audited writes. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured lists.create · HTTP 201

Action input

{
  "name": "Other"
}

Actual local response

{
  "list": {
    "id": "list_2",
    "name": "Other",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T09:00:00.000Z",
    "updatedAt": "2026-10-01T09:00:00.000Z",
    "archivedAt": null
  }
}

Source test: sourcing workflows over the published actions > creates, lists, gets, updates and deletes a workflow with audited writes. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured lists.create · HTTP 201

Action input

{
  "name": "Founders"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Founders",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-06T08:30:00.000Z",
    "updatedAt": "2026-10-06T08:30:00.000Z",
    "archivedAt": null
  }
}

Source test: enrollment routes > enrolls a list and reports every contact it skipped and why. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured lists.create · HTTP 201

Action input

{
  "name": "Targets"
}

Actual local response

{
  "list": {
    "id": "list_1",
    "name": "Targets",
    "description": null,
    "memberCount": 0,
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": null
  }
}

Source test: contacts.qualify > qualifies a list's first unqualified or stale active members, bounded to 25. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Effects and response meaning

  • Creates a new empty list with generated id, trimmed name, nullable description and memberCount:0. Returns list with HTTP 201. Does not add contacts or send messages.
  • No idempotency key or unique-name guarantee exists in this handler. A blind retry can create another list with the same name.

Verify the result

  • Read lists.get using returned list.id and compare name, description, memberCount and archivedAt. Retain its exact id for membership changes.

Recover

After an uncertain creation, rediscover lists in the same workspace and compare name, description and creation time. These values do not uniquely prove identity; if ambiguous, stop rather than retry or archive a guessed record. Archive only an exactly identified unwanted list through a separate approved action.

Refused responses

Captured lists.create · HTTP 403

Refused input; do not execute

{}

Actual local response

{
  "error": {
    "code": "permission_denied",
    "message": "The credential lacks workspace:write.",
    "details": {
      "requiredPermission": "workspace:write"
    }
  }
}

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.

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.

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.