Topolo Docs Topolo Platform
Open workspace

Get outreach campaign

Read one discovered outreach campaign and its current state.

Outcome

Read one discovered outreach campaign and its current state.

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

  • Read campaigns.list in the same workspace and select campaigns[].id. Archived campaigns require status=archived on that discovery read.
topolo whoami --json
topolo actions get app_topolo_engage.campaigns.get --json
topolo workspaces list topolo-engage --json

Input fields

FieldRequiredMeaning and constraints
idYesRequired campaign identifier returned by campaigns.list or campaigns.create; trimmed non-empty string up to 128 characters.

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.campaigns.get --data @payload.json --json
topolo actions plan app_topolo_engage.campaigns.get --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.campaigns.get --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 campaigns.get · HTTP 200

Action input

{
  "id": "eng_cmp_1"
}

Actual local response

{
  "campaign": {
    "id": "eng_cmp_1",
    "name": "Self-test",
    "goal": null,
    "channel": "email",
    "status": "draft",
    "isTest": false,
    "createdBy": "user_1",
    "updatedBy": "user_1",
    "createdAt": "2026-10-06T08:30:00.000Z",
    "updatedAt": "2026-10-06T08:30:00.000Z",
    "archivedAt": null
  }
}

Source test: campaign test flag > is set on create or update and returned on the campaign. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured campaigns.get · HTTP 200

Action input

{
  "id": "eng_cmp_1"
}

Actual local response

{
  "campaign": {
    "id": "eng_cmp_1",
    "name": "Q4 outreach",
    "goal": "Book demos",
    "channel": "email",
    "status": "draft",
    "isTest": false,
    "createdBy": "user_1",
    "updatedBy": "user_1",
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": null
  }
}

Source test: campaign routes > creates, lists, reads, edits and transitions a campaign (happy path). Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Captured campaigns.get · HTTP 200

Action input

{
  "id": "eng_cmp_1"
}

Actual local response

{
  "campaign": {
    "id": "eng_cmp_1",
    "name": "Mine",
    "goal": null,
    "channel": "email",
    "status": "draft",
    "isTest": false,
    "createdBy": "user_1",
    "updatedBy": "user_1",
    "createdAt": "2026-10-01T00:00:00.000Z",
    "updatedAt": "2026-10-01T00:00:00.000Z",
    "archivedAt": null
  }
}

Source test: campaign routes > returns 404 for a campaign that lives in another workspace. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Effects and response meaning

  • Reads a single workspace-scoped campaign at response campaign. A campaign belonging to another workspace returns not_found rather than exposing its content.

Verify the result

  • Compare response campaign.id with the requested id. Retain name, goal, isTest, status, updatedAt and archivedAt before planning an edit or transition.

Recover

Retry the read after a transient failure with the same discovered id and workspace. On not_found, rediscover within that workspace rather than guessing other resource contexts.

Refused responses

Captured campaigns.get · HTTP 404

Action input

{
  "id": "eng_cmp_1"
}

Actual local response

{
  "error": {
    "code": "not_found",
    "message": "Campaign was not found in this workspace."
  }
}

Source test: campaign routes > returns 404 for a campaign that lives in another workspace. Actual route handlers with SQLite repositories; synthetic identity/workspace grants and provider ports.

Error recovery

  • HTTP 404 not_found: Rediscover the campaign using campaigns.list in the same authorized workspace, including status=archived when appropriate. Do not guess another organization or workspace.

Evidence and limits

  • contracts/campaigns.mjs

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

  • apps/api/src/campaigns/campaigns-handlers.ts

  • apps/api/src/campaigns/campaigns-domain.ts

  • apps/api/src/campaigns/campaigns-repository.ts

  • apps/api/test/campaigns-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.