Topolo Docs Topolo Platform
Open workspace

Update series dashboard

Replaces the saved dashboard object or restores supported template defaults; it does not merge a partial dashboard.

Outcome

Replaces the saved dashboard object or restores supported template defaults; it does not merge a partial dashboard.

Before you start

  • Verify identity, environment and the intended organization before discovery.
  • Discover the published series:write permission and the target policy.
  • Select an accessible canonical Auth workspace and set WORKSPACE_ID to its returned id. Workspace binding is separate from input.
  • Review and confirm the exact unchanged plan before execution. Example identifiers grant no live authority.

Discover the target

topolo whoami --json
topolo workspaces list topolo-quro --json
topolo actions get app_topolo_quro.series.dashboard.update --detail --json
  • id: Exact returned series or export id converted to a string. Discover series through series.list; retain export ids from exports.create.

Request

PUT /series/{id}/dashboard

Inspect parameters and test this action.

Input fields

FieldRequiredMeaning
idYesExact returned series or export id converted to a string. Discover series through series.list; retain export ids from exports.create.
dashboardNoComplete free-form dashboard object, replacing the prior saved state. Save and compare the full prior object before changing it.
resetToDefaultNoRestore supported template defaults. A series with no supported template still needs a dashboard object.

Worked examples

Actual exported Quro Worker with local Miniflare D1/KV and every committed app/analytics migration. Auth, service tokens, Nexus, destination probes and platform archival are synthetic responses; outbound fetch is sealed. Notifications remain in the local outbox. No live redirect propagation, QR scan, destination health, provider delivery, archival or production erasure is established.

Save reviewed input as payload.json, replacing fixture identifiers through discovery.

topolo actions validate app_topolo_quro.series.dashboard.update --data @payload.json --json
topolo actions plan app_topolo_quro.series.dashboard.update --resource-type workspace --resource-id "$WORKSPACE_ID" --data @payload.json --confirm --json
topolo actions call app_topolo_quro.series.dashboard.update --resource-type workspace --resource-id "$WORKSPACE_ID" --data @payload.json --confirm --detail --json

MCP uses the same reviewed input and separately discovered resource binding:

{
  "tool": "topolo_prepare_action",
  "arguments": {
    "actionId": "app_topolo_quro.series.dashboard.update",
    "input": {
      "id": "1",
      "dashboard": {
        "layout": "fixture",
        "widgets": []
      }
    },
    "resourceType": "workspace",
    "resourceId": "ws_quro_fixture",
    "confirm": true
  }
}
{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_quro.series.dashboard.update",
    "input": {
      "id": "1",
      "dashboard": {
        "layout": "fixture",
        "widgets": []
      }
    },
    "resourceType": "workspace",
    "resourceId": "ws_quro_fixture",
    "confirm": true,
    "detail": true
  }
}

Worked response 1 · HTTP 200

Input · payload.json:

{
  "id": "1",
  "dashboard": {
    "layout": "fixture",
    "widgets": []
  }
}

Captured SDK response:

{
  "success": true,
  "data": {
    "dashboard": {
      "layout": "fixture",
      "widgets": []
    },
    "updated_at": "2026-10-06T11:16:12.192Z"
  }
}

HTTP 200. Read series.dashboard.get and compare the complete dashboard and returned update time. resetToDefault requires a supported template; otherwise provide dashboard.

Worked response 2 · HTTP 400 · Dashboard state is required

Input · payload.json:

{
  "id": "1"
}

Captured SDK response:

{
  "success": false,
  "error": "Dashboard state is required"
}

HTTP 400. Correct the reviewed payload using inputSchema and the returned handler message.

Worked response 3 · HTTP 200

Input · payload.json:

{
  "id": "3",
  "dashboard": {
    "layout": "reviewed-fixture"
  }
}

Captured SDK response:

{
  "success": true,
  "data": {
    "dashboard": {
      "layout": "reviewed-fixture"
    },
    "updated_at": "2026-10-06T11:16:12.873Z"
  }
}

HTTP 200. Read series.dashboard.get and compare the complete dashboard and returned update time. resetToDefault requires a supported template; otherwise provide dashboard.

Worked response 4 · HTTP 200 · Reset to template defaults

Input · payload.json:

{
  "id": "3",
  "resetToDefault": true
}

Captured SDK response:

{
  "success": true,
  "data": {
    "dashboard": {
      "layout": "marathon",
      "title": "Marathon Runner Tracking",
      "metrics": [
        {
          "id": "total_participants",
          "label": "Total Participants",
          "value": 0,
          "icon": "🏃‍♂️",
          "type": "counter"
        },
        {
          "id": "active_runners",
          "label": "Active Runners",
          "value": 0,
          "icon": "⚡",
          "type": "counter",
          "color": "success"
        },
        {
          "id": "finished_runners",
          "label": "Finished",
          "value": 0,
          "icon": "🏁",
          "type": "counter",
          "color": "primary"
        },
        {
          "id": "avg_pace",
          "label": "Average Pace",
          "value": "0:00/km",
          "icon": "⏱️",
          "type": "text"
        }
      ],
      "sections": [
        {
          "id": "live_tracking",
          "title": "Live Tracking",
          "type": "timeline",
          "data": [
            {
              "id": "sample_1",
              "timestamp": "2026-10-06T11:16:11.435Z",
              "runner": "Sample Runner #001",
              "checkpoint": "Start Line",
              "time": "00:00:00",
              "status": "started"
            }
          ]
        },
        {
          "id": "leaderboard",
          "title": "Current Leaderboard",
          "type": "table",
          "headers": [
            "Position",
            "Runner",
            "Time",
            "Pace"
          ],
          "data": [
            [
              "1",
              "Sample Runner #001",
              "00:00:00",
              "0:00/km"
            ]
          ]
        },
        {
          "id": "checkpoints",
          "title": "Checkpoint Status",
          "type": "progress",
          "data": [
            {
              "name": "Start Line",
              "completed": 0,
              "total": 0
            },
            {
              "name": "5km Mark",
              "completed": 0,
              "total": 0
            },
            {
              "name": "10km Mark",
              "completed": 0,
              "total": 0
            },
            {
              "name": "21km Mark",
              "completed": 0,
              "total": 0
            },
            {
              "name": "Finish Line",
              "completed": 0,
              "total": 0
            }
          ]
        }
      ],
      "actions": [
        {
          "id": "add_checkpoint",
          "label": "Add Checkpoint",
          "icon": "📍",
          "type": "primary"
        },
        {
          "id": "export_results",
          "label": "Export Results",
          "icon": "📊",
          "type": "secondary"
        },
        {
          "id": "send_alerts",
          "label": "Send Alerts",
          "icon": "🚨",
          "type": "warning"
        }
      ]
    },
    "updated_at": "2026-10-06T11:16:12.885Z"
  }
}

HTTP 200. Read series.dashboard.get and compare the complete dashboard and returned update time. resetToDefault requires a supported template; otherwise provide dashboard.

Worked response 5 · HTTP 400 · Invalid series ID

Input · payload.json:

{
  "id": "not-numeric"
}

Captured SDK response:

{
  "success": false,
  "error": "Invalid series ID"
}

HTTP 400. Correct the reviewed payload using inputSchema and the returned handler message.

Worked response 6 · HTTP 404 · Series not found

Input · payload.json:

{
  "id": "999999",
  "dashboard": {}
}

Captured SDK response:

{
  "success": false,
  "error": "Series not found"
}

HTTP 404. Discover the exact record id or slug in the same workspace before retrying.

Worked response 7 · HTTP 400 · Dashboard state is required

Input · payload.json:

{
  "id": "1",
  "resetToDefault": true
}

Captured SDK response:

{
  "success": false,
  "error": "Dashboard state is required"
}

HTTP 400. Correct the reviewed payload using inputSchema and the returned handler message.

Verify the result

  • Read series.dashboard.get and compare the complete dashboard and returned update time. resetToDefault requires a supported template; otherwise provide dashboard.

Errors and recovery

  • HTTP 400 · http_error: Correct the reviewed payload using inputSchema and the returned handler message.
  • HTTP 404 · http_error: Discover the exact record id or slug in the same workspace before retrying.
  • HTTP 401 · auth_error: Authenticate again in the intended environment and organization.
  • HTTP 403 · action_permission_required: Inspect the actual refusal. The action permission and the verified workspace access are both required; a caller cannot name an ungranted workspace.

Inspect the original handler body as well as the SDK error code. These are observed local refusals, not an exhaustive provider-failure list.

Recovery boundary

Retain the complete reviewed prior dashboard and restore it with this action if needed. The free-form dashboard object does not validate a product-specific widget layout.

  • Get series dashboard: Reads the series identity and saved dashboard; supported templates can supply a default dashboard when no saved state exists.

Evidence

Actual exported Quro Worker with local Miniflare D1/KV and every committed app/analytics migration. Auth, service tokens, Nexus, destination probes and platform archival are synthetic responses; outbound fetch is sealed. Notifications remain in the local outbox. No live redirect propagation, QR scan, destination health, provider delivery, archival or production erasure is established.