Outcome
Edit description or logo with explicit local-role checks, partial-write recovery and Auth-owned naming.
Action: app_topolo_socialize.brands.update.
Before you start
- Verify production, the original signed-in principal and intended organization. Socialize calls a canonical Auth workspace a brand; do not fabricate a brand id from a name or change the caller.
- Use only actual discovered workspace grants and the published action permission. API-key workspace bindings further narrow the grant; organization membership alone is insufficient. Keep resource context separate from action input.
- Published permission: app_topolo_socialize.accounts:write. Review, validate and plan the exact edit before confirming it.
Find the workspace
- Read brands.get first and retain previous description/logo plus the verified workspace/organization. Confirm intended edits and local owner/admin access; do not switch to an elevated credential to bypass a refusal.
Request
PUT /api/brands/{id}
{
"id": "ws_socialize_example",
"description": "Reviewed editorial profile"
}
Input fields are exactly those in the current published action schema. The advertised name field is ignored by this pinned source; use only description/logo for this profile edit.
For an authorized CLI operation, pin the actual context/environment, discover the workspace, then use the actual values in place of the placeholders below. These commands are illustrative and were not executed against Socialize.
TOPOLO_CONTEXT="org:<verified-org-id>" topolo --env production actions validate app_topolo_socialize.brands.update --data '<reviewed-input-json>' --json
TOPOLO_CONTEXT="org:<verified-org-id>" topolo --env production actions plan app_topolo_socialize.brands.update --resource-type workspace --resource-id '<verified-workspace-id>' --data '<reviewed-input-json>' --confirm --json
Interpret the response
- This handler edits description and logoUrl only. The current published input/description also advertises name, but UpdateBrandSchema strips it and BrandService has no name update. Do not use this action to rename a workspace or claim a successful name edit.
- Workspace identity/name/slug/default remain Auth-owned. Use the supported workspace rename workflow after its actual caller policy and approval checks.
- description is optional with maximum500characters; an empty string clears it. logoUrl must pass the route URL validator; empty string/null is not a documented clearing mechanism.
- The route returns a bare profile through getBrand. memberCount counts active local members; it is not an update receipt for Auth grants.
Effects
- Workspace authorization can insert a local brand mirror or reactivate/synchronize its organization/status before the approved profile edit. The published update action is a confirmed write (readOnly:false), not a read operation.
- After workspace authorization, BrandService additionally requires an active local owner/admin membership for the original caller. This method does not apply the platform-access bypass used by some member-management methods. Generic metadata permission or org ownership does not guarantee this local check passes.
- Supplied description/logo fields update the local brand timestamp, then brand_updated activity is inserted, then the profile is read. No enclosing transaction is shown. An activity/read failure can follow a successful profile update; do not assume an error rolled it back.
- If neither supported field is supplied, the service returns the profile without an explicit profile UPDATE or activity insertion, but still checks local manage permission and authorization mirror synchronization. A name-only request does not rename anything.
- This source route does not invalidate brands.list profile caches. Use brands.get for immediate verification; a stale listing is not proof the update failed.
Worked examples
Every example below is source-derived, synthetic and unrun. Placeholder ids, emails and timestamps confer no real authority. Returned shape illustrates the pinned handler; the published structural schema alone does not guarantee application semantics.
Change an approved description
Source-derived synthetic and unrun. Assumes original caller has both the platform workspace grant and active local owner/admin membership.
Request:
{
"id": "ws_socialize_example",
"description": "Reviewed editorial profile"
}
Illustrative successful response:
{
"id": "ws_socialize_example",
"description": "Reviewed editorial profile",
"logoUrl": "",
"memberCount": 2,
"organizationId": "org_example",
"createdAt": "2026-10-21T00:00:00.000Z",
"updatedAt": "2026-10-21T13:00:00.000Z"
}
Verify description through brands.get; no workspace rename or notification is implied.
Clear the description
Source-derived synthetic and unrun. Clearing is explicitly approved; illustrative timestamps are not captured execution.
Request:
{
"id": "ws_socialize_example",
"description": ""
}
Illustrative successful response:
{
"id": "ws_socialize_example",
"description": "",
"logoUrl": "",
"memberCount": 2,
"organizationId": "org_example",
"createdAt": "2026-10-21T00:00:00.000Z",
"updatedAt": "2026-10-21T13:01:00.000Z"
}
Verify the returned empty description while preserving intended logo and Auth workspace name.
Refusals and recovery
| Status | Source-specific condition | Next step |
|---|---|---|
| 400 | /problems/validation-error | Use the original verified organization and valid resource-binding context. The route-specific body validator may instead return validation_error; correct only the reported fields. |
| 403 | workspace_forbidden | Named workspace absent or inaccessible; re-discover the original allowed workspace, without guessed fallback or widened authority. |
| 503 | workspace_unresolved | Auth could not verify workspace access. Preserve the error and request id; do not interpret it as an empty authorized list. |
| 400 | failed_to_update_brand | A generic failure, including Insufficient permissions to update brand, is serialized by this route with default400. Reconcile the actual message/state; do not fabricate a403/409 mapping or assume rollback. |
| 400 | validation_error | Correct only supported description/logo fields from returned issues; name is not a supported persisted field. |
| 404 | brand_not_found | Authorized active local profile was not returned. Reconcile the exact canonical workspace; do not try another unverified identity. |
Outer authentication, permission and rate-limit refusals can differ from handler responses. Retain actual codes/request ids and use current discovery; no simulated refusal here is a deployed carrier test.
Verify the result
- Call brands.get in the same workspace and compare only approved description/logo fields. Reconcile persisted fields and activity separately after an uncertain error before deciding whether any repair is needed.
- A prior valid URL/description may be restored only as a separately authorized update after reconciliation. Restoring data does not remove activity or reverse an external effect, and an earlier empty logo cannot be cleared by inventing an undocumented null/empty payload.
Related actions
Change log
2026-10-21: Added a source-qualified task guide with paired agent instructions, source-derived examples, workspace boundaries, actual response shape and side-effect/recovery notes. Reviewed source: f8e30bad6947f868302f24e9cb31b6a2bdd1fbf6; current catalog marker: bc22ce7a2ceaa4396388794c4d42895c777bed76. Their deployed serving association has not been established. No action execution, provider effect or test capture is claimed.