Topolo Docs Topolo Platform
Open workspace

Record Success account health

Save a score from 0 to 100, append history and enqueue a health-change event on every call, including identical repeats. Downward threshold crossing creates a risk; upward recovery resolves open risks.

Outcome

Save a score from 0 to 100, append history and enqueue a health-change event on every call, including identical repeats. Downward threshold crossing creates a risk; upward recovery resolves open risks.

Before you start

  • Verify the authenticated identity, exact environment and pinned approved organization context before preparing an action.
  • The published application permission is workspace:write. Discover a granted Success workspace and bind that exact resource. Supplied identifiers do not grant access.
  • Authorize the documented mirror, notification, metering, privacy or archival effects before CLI --confirm or MCP confirm:true. A GET request can initialize a local mirror.

Discover the target

topolo whoami --json
topolo actions get app_topolo_success.accounts.health.update --detail --json
topolo resources topolo-success --json
topolo workspaces list topolo-success --json
  • Select the exact granted workspace id as SUCCESS_WORKSPACE_ID. Fixture ids authorize no live operation.
  • Discover account ids through accounts.list or the reviewed accounts.create response.

Request

PUT /api/accounts/{accountId}/health

Save action input as payload.json. Inspect the plan for the exact path, query and body. Set SUCCESS_WORKSPACE_ID from granted resource discovery.

Inspect and test this action in the signed action console, then perform the verification below.

Input fields

FieldRequiredTypeConstraints
accountIdRequiredstringAccount id returned by accounts.list or accounts.create in this same granted workspace.; {"minLength":1}
scoreRequiredintegerNew integer health score from 0 to 100; every call appends history and a notification event, including repeats.; {"minimum":0,"maximum":100}

Exact input schema:

{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "accountId": {
      "type": "string",
      "minLength": 1,
      "description": "Account id returned by accounts.list or accounts.create in this same granted workspace."
    },
    "score": {
      "type": "integer",
      "minimum": 0,
      "maximum": 100,
      "description": "New integer health score from 0 to 100; every call appends history and a notification event, including repeats."
    }
  },
  "required": [
    "accountId",
    "score"
  ],
  "additionalProperties": false
}

Effects

  • After static permission and platform workspace authorization, the route inserts the local identity-only workspace mirror if absent; even GET listing is a potential write.
  • Every successful call updates account score/status and appends a new history row and health-change outbox event. At or below the threshold means at_risk; descending from above additionally creates a risk/event.
  • Recovery from at/below to above resolves open risks; response riskId is null unless this call crosses into risk.
  • The call attempts a flush of up to 100 oldest pending notification rows across the whole Success environment, including other organizations. State is committed before this flush; failure does not undo it. Counts represent transport/outbox outcomes, not recipient delivery.

Interpret the response

Use response path $.account.id for success_account. An empty list does not discover a target.

Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state. Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

The success schema below was checked against captured handler responses. Delegated Auth profile fields and sanitized notification payload fields can vary; exact outer envelopes and SQL row fields are source-reviewed. Error examples retain their actual refusal shapes.

Success schema:

{
  "type": "object",
  "properties": {
    "account": {
      "type": "object",
      "properties": {
        "id": {
          "type": "string",
          "description": "Source-defined string field."
        },
        "organization_id": {
          "type": "string",
          "description": "Source-defined string field."
        },
        "workspace_id": {
          "type": "string",
          "description": "Source-defined string field."
        },
        "created_at": {
          "type": "string",
          "description": "Source-defined string field."
        },
        "updated_at": {
          "type": "string",
          "description": "Source-defined string field."
        },
        "name": {
          "type": "string",
          "description": "Source-defined string field."
        },
        "owner_user_id": {
          "type": "string",
          "description": "Source-defined string field."
        },
        "health_score": {
          "type": "integer",
          "minimum": 0,
          "maximum": 100
        },
        "risk_threshold": {
          "type": "integer",
          "minimum": 0,
          "maximum": 100
        },
        "risk_status": {
          "type": "string",
          "enum": [
            "healthy",
            "at_risk"
          ]
        },
        "renewal_at": {
          "anyOf": [
            {
              "type": "string",
              "description": "Source-defined string field."
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "required": [
        "id",
        "organization_id",
        "workspace_id",
        "created_at",
        "updated_at",
        "name",
        "owner_user_id",
        "health_score",
        "risk_threshold",
        "risk_status",
        "renewal_at"
      ],
      "additionalProperties": false
    },
    "riskId": {
      "anyOf": [
        {
          "type": "string",
          "description": "Source-defined string field."
        },
        {
          "type": "null"
        }
      ]
    },
    "notifications": {
      "type": "object",
      "properties": {
        "pending": {
          "type": "integer",
          "description": "Counts for the environment-wide pending notification flush, not proof of recipient delivery."
        },
        "sent": {
          "type": "integer",
          "description": "Counts for the environment-wide pending notification flush, not proof of recipient delivery."
        },
        "rejected": {
          "type": "integer",
          "description": "Counts for the environment-wide pending notification flush, not proof of recipient delivery."
        },
        "failed": {
          "type": "integer",
          "description": "Counts for the environment-wide pending notification flush, not proof of recipient delivery."
        }
      },
      "required": [
        "pending",
        "sent",
        "rejected",
        "failed"
      ],
      "additionalProperties": false
    }
  },
  "required": [
    "account",
    "riskId",
    "notifications"
  ],
  "additionalProperties": false
}

Worked examples

Actual exported Worker responses captured with real local SQLite D1 and all committed migrations, synthetic Auth identity/grants, simulated Notify/Nexus and canonical archive transport. Fixture ids are examples only. No live notification delivery, metering acceptance, privacy erasure, workspace archive or deployment is established by these tests. Refused examples demonstrate boundaries and must not be executed as successful workflows.

Successful request

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: notification failure retains account mutation.

Input · payload.json:

{
  "accountId": "successacct_5e505e19-030e-4268-8812-1bcf1968e2d8",
  "score": 55
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_success.accounts.health.update",
    "input": {
      "accountId": "successacct_5e505e19-030e-4268-8812-1bcf1968e2d8",
      "score": 55
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "account": {
    "id": "successacct_5e505e19-030e-4268-8812-1bcf1968e2d8",
    "organization_id": "org_success_fixture",
    "workspace_id": "ws_success_fixture",
    "name": "Example Customer",
    "owner_user_id": "usr_success_fixture",
    "health_score": 55,
    "risk_threshold": 40,
    "risk_status": "healthy",
    "renewal_at": "2027-03-31T00:00:00Z",
    "created_at": "2026-10-04T05:10:04.828Z",
    "updated_at": "2026-10-04T05:10:04.905Z"
  },
  "riskId": null,
  "notifications": {
    "pending": 1,
    "sent": 0,
    "rejected": 0,
    "failed": 1
  }
}

HTTP 200. Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state. Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

Another supported request

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: accounts.health.update.

Input · payload.json:

{
  "accountId": "successacct_cc555431-d2fb-41d4-b7b7-bd0045eecc14",
  "score": 35
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_success.accounts.health.update",
    "input": {
      "accountId": "successacct_cc555431-d2fb-41d4-b7b7-bd0045eecc14",
      "score": 35
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "account": {
    "id": "successacct_cc555431-d2fb-41d4-b7b7-bd0045eecc14",
    "organization_id": "org_success_fixture",
    "workspace_id": "ws_success_fixture",
    "name": "Example Customer",
    "owner_user_id": "usr_success_fixture",
    "health_score": 35,
    "risk_threshold": 40,
    "risk_status": "at_risk",
    "renewal_at": "2027-03-31T00:00:00Z",
    "created_at": "2026-10-04T05:10:05.376Z",
    "updated_at": "2026-10-04T05:10:05.394Z"
  },
  "riskId": "successrisk_086300de-dd7a-4d5b-92db-143e4ce107d2",
  "notifications": {
    "pending": 2,
    "sent": 2,
    "rejected": 0,
    "failed": 0
  }
}

HTTP 200. Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state. Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

Another supported request

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: recovery resolves open risk.

Input · payload.json:

{
  "accountId": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
  "score": 75
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_success.accounts.health.update",
    "input": {
      "accountId": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
      "score": 75
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "account": {
    "id": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
    "organization_id": "org_success_fixture",
    "workspace_id": "ws_success_fixture",
    "name": "Example Customer",
    "owner_user_id": "usr_success_fixture",
    "health_score": 75,
    "risk_threshold": 40,
    "risk_status": "healthy",
    "renewal_at": "2027-03-31T00:00:00Z",
    "created_at": "2026-10-04T05:10:03.146Z",
    "updated_at": "2026-10-04T05:10:03.285Z"
  },
  "riskId": null,
  "notifications": {
    "pending": 1,
    "sent": 1,
    "rejected": 0,
    "failed": 0
  }
}

HTTP 200. Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state. Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

Refused request · HTTP 400

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: invalid score.

Input · payload.json:

{
  "accountId": "missing",
  "score": 101
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json

Captured local response · HTTP 400:

{
  "success": false,
  "error": {
    "code": "invalid_action_input",
    "message": "Invalid action input for \"accounts.health.update\".",
    "action": "accounts.health.update",
    "issues": [
      {
        "path": "score",
        "message": "Too big: expected number to be <=100",
        "code": "too_big"
      }
    ]
  }
}

HTTP 400. The handler refused this request. Resolve its exact cause before retrying; input validation can reject an invalid fixture before it reaches the handler.

Refused request · HTTP 404

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: missing account.

Input · payload.json:

{
  "accountId": "missing",
  "score": 35
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json

Captured local response · HTTP 404:

{
  "error": "account_not_found"
}

HTTP 404. The handler refused this request. Resolve its exact cause before retrying; input validation can reject an invalid fixture before it reaches the handler.

Another supported request

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: same score still appends history and event.

Input · payload.json:

{
  "accountId": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
  "score": 40
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_success.accounts.health.update",
    "input": {
      "accountId": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
      "score": 40
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "account": {
    "id": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
    "organization_id": "org_success_fixture",
    "workspace_id": "ws_success_fixture",
    "name": "Example Customer",
    "owner_user_id": "usr_success_fixture",
    "health_score": 40,
    "risk_threshold": 40,
    "risk_status": "at_risk",
    "renewal_at": "2027-03-31T00:00:00Z",
    "created_at": "2026-10-04T05:10:03.146Z",
    "updated_at": "2026-10-04T05:10:03.239Z"
  },
  "riskId": null,
  "notifications": {
    "pending": 1,
    "sent": 1,
    "rejected": 0,
    "failed": 0
  }
}

HTTP 200. Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state. Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

Another supported request

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: global pending outbox is flushed.

Input · payload.json:

{
  "accountId": "successacct_5e505e19-030e-4268-8812-1bcf1968e2d8",
  "score": 60
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_success.accounts.health.update",
    "input": {
      "accountId": "successacct_5e505e19-030e-4268-8812-1bcf1968e2d8",
      "score": 60
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "account": {
    "id": "successacct_5e505e19-030e-4268-8812-1bcf1968e2d8",
    "organization_id": "org_success_fixture",
    "workspace_id": "ws_success_fixture",
    "name": "Example Customer",
    "owner_user_id": "usr_success_fixture",
    "health_score": 60,
    "risk_threshold": 40,
    "risk_status": "healthy",
    "renewal_at": "2027-03-31T00:00:00Z",
    "created_at": "2026-10-04T05:10:04.828Z",
    "updated_at": "2026-10-04T05:10:04.858Z"
  },
  "riskId": null,
  "notifications": {
    "pending": 2,
    "sent": 2,
    "rejected": 0,
    "failed": 0
  }
}

HTTP 200. Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state. Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

Another supported request

Actual exported Worker response with real local SQLite D1, synthetic Auth/grants and simulated Notify/Nexus/archive transport; no live delivery or deployment proof. Captured scenario: threshold crossing.

Input · payload.json:

{
  "accountId": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
  "score": 40
}

CLI:

topolo actions validate app_topolo_success.accounts.health.update --data @payload.json --json
topolo actions plan app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --json
topolo actions call app_topolo_success.accounts.health.update --resource-type workspace --resource-id "$SUCCESS_WORKSPACE_ID" --data @payload.json --confirm --json

MCP tool and arguments:

{
  "tool": "topolo_call_action",
  "arguments": {
    "actionId": "app_topolo_success.accounts.health.update",
    "input": {
      "accountId": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
      "score": 40
    },
    "resourceType": "workspace",
    "resourceId": "<identifier returned by granted resource discovery>",
    "confirm": true
  }
}

Captured local response · HTTP 200:

{
  "account": {
    "id": "successacct_854a49b4-6ddd-4b79-8325-8299814747e6",
    "organization_id": "org_success_fixture",
    "workspace_id": "ws_success_fixture",
    "name": "Example Customer",
    "owner_user_id": "usr_success_fixture",
    "health_score": 40,
    "risk_threshold": 40,
    "risk_status": "at_risk",
    "renewal_at": "2027-03-31T00:00:00Z",
    "created_at": "2026-10-04T05:10:03.146Z",
    "updated_at": "2026-10-04T05:10:03.188Z"
  },
  "riskId": "successrisk_dacc79ce-3f73-4d49-a544-12dc0fe841a3",
  "notifications": {
    "pending": 2,
    "sent": 2,
    "rejected": 0,
    "failed": 0
  }
}

HTTP 200. Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state. Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

Verify the result

  • Verify account.id, health_score and risk_status; riskId can validly be null. Read accounts.list in the same granted workspace to verify current state.
  • Inspect notifications.pending/sent/rejected/failed without treating them as a recipient receipt. History and events already committed survive notification failures.

Errors and recovery

  • invalid_action_input (HTTP 400): Correct only the input paths reported by the runtime or CLI validator; retain action id and exact context.
  • action_permission_required (HTTP 403): The verified credential lacks the action permission. Stop this action and request the appropriate authorized grant; an identifier or organization ownership does not grant it.
  • organization_required (HTTP 403): Verify the authorized organization context; personal scope cannot operate on organization-owned Success data.
  • workspace_required (HTTP 400): Discover an authorized app-scoped workspace and pass its resource binding. API keys without a workspace resource are refused.
  • workspaces_unavailable (HTTP 503): Preserve the request id and report unavailable platform grants or database binding; do not invent a default workspace.
  • account_not_found (HTTP 404): Use accounts.list in the same granted workspace; ids from another workspace or organization are refused.

Auth, action-input validation and platform resource resolution can refuse a request before its handler. Retain the exact error, request id and context; requesting another context is not a legitimate way to bypass a refusal.

Recovery boundary

Only after a new authorization, submit the correct score. This appends another history/event and can emit a new risk crossing; it does not erase previous history or recall notifications. Repeating the same score is not idempotent.

  • List Success customer accounts: List all customer accounts in the authorized workspace, ordered by latest update and then name. There is no pagination; the request can create the local workspace identity mirror.
  • Create Success playbook task: Create a pending task for an authorized account with a required ISO due time. Immediate creation does not complete the task or send its due reminder; scheduled processing handles due events later.

Evidence

Actual exported Worker responses captured with real local SQLite D1 and all committed migrations, synthetic Auth identity/grants, simulated Notify/Nexus and canonical archive transport. Fixture ids are examples only. No live notification delivery, metering acceptance, privacy erasure, workspace archive or deployment is established by these tests. Capture digests and test scenarios are retained in the source fixture records.