> ## Documentation Index
> Fetch the complete documentation index at: https://docs.glider.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin Control Plane Snapshot

> Internal-only endpoint for projecting authoritative portfolio approvals and runs into the Cloudflare control-plane

This endpoint returns authoritative control-plane snapshots for a supplied user
and portfolio set. It is intended for internal control-plane sync and pull
flows, not public product traffic.

## Scope

* Internal-only
* Protected by `ADMIN_AUTH_SECRET_TOKEN`
* Validates that every requested portfolio is owned by the supplied `userId`

## Request

Headers:

* `Authorization: Bearer <ADMIN_AUTH_SECRET_TOKEN>`
* `Content-Type: application/json`

Path params:

* `userId`: canonical platform user id whose linked addresses define portfolio ownership

Body:

```json theme={null}
{
  "portfolioIds": ["pf_123", "pf_456"]
}
```

Rules:

* `portfolioIds` must be a non-empty array
* maximum 200 portfolio ids per request
* the route returns `403` if any requested portfolio is not linked to the supplied user

## Response

```json theme={null}
{
  "userId": "usr_123",
  "portfolios": [
    {
      "portfolioId": "pf_123",
      "projectionVersion": "00000000000000000042",
      "policyVersion": "policy-config:2026-04-14T01:00:00.000Z",
      "snapshotHash": "context:ctx_123",
      "controlPlaneSummary": {
        "convergence": {
          "approvalId": "approval_1",
          "executionStatus": null,
          "proposalId": null,
          "runId": null,
          "state": "awaiting_review",
          "summary": "1 portfolio change is waiting for review.",
          "targetId": "proposal_1",
          "targetType": "portfolio_update",
          "updatedAt": "2026-04-14T01:00:00.000Z"
        },
        "reviewQueue": {
          "activeApprovalCount": 1,
          "awaitingReviewCount": 1,
          "blockedCount": 0,
          "failedCount": 0,
          "latestItem": {
            "approvalId": "approval_1",
            "status": "pending",
            "summary": "Review and approve the rebalance.",
            "targetId": "proposal_1",
            "targetType": "portfolio_update",
            "title": "Approve rebalance",
            "updatedAt": "2026-04-14T01:00:00.000Z"
          },
          "movingCount": 1,
          "queuedCount": 0
        }
      },
      "approvals": [
        {
          "id": "approval_1",
          "portfolioId": "pf_123",
          "status": "pending",
          "title": "Approve rebalance",
          "summary": "Review and approve the rebalance.",
          "requestedBy": "portfolio-control-plane",
          "requestedAt": "2026-04-14T01:00:00.000Z",
          "resolvedAt": null,
          "resolvedBy": null,
          "targetId": "proposal_1",
          "targetType": "portfolio_update"
        }
      ],
      "runs": [
        {
          "id": "run_1",
          "portfolioId": "pf_123",
          "kind": "rebalance",
          "status": "awaiting_user",
          "title": null,
          "summary": "Waiting for approval.",
          "approvalId": "approval_1",
          "sourceId": "request_1",
          "sourceKind": "rebalance_request",
          "createdAt": "2026-04-14T00:59:00.000Z",
          "updatedAt": "2026-04-14T01:00:00.000Z"
        }
      ]
    }
  ]
}
```

## Runtime Behavior

`platform-api` resolves the supplied `userId` to linked wallet addresses, then
asks the ownership reader for canonically owned portfolio ids. Only after that
ownership check passes does it call the portfolio control-plane facade to
allocate a persisted per-portfolio revision and read the snapshot source rows
in the same database transaction. Portfolio valuation summaries and optional
account intelligence are also materialized before that transaction releases its
per-portfolio revision locks, so the complete payload follows the same ordering.
`projectionVersion` is the allocated revision encoded as a required, zero-padded
20-digit string so consumers can compare it lexicographically. Read-only summary
and dashboard paths do not allocate projection revisions.

The current route also emits stable portfolio metadata when available:

* `policyVersion`: derived from the stored smart-portfolio policy config
* `snapshotHash`: derived from the latest control-plane context snapshot
* `controlPlaneSummary`: the canonical portfolio `convergence` plus `reviewQueue` summary already used by shared services

`projectionVersion` is always present. If no policy config or context snapshot
exists yet, their identity fields return `null`.

This route is the current upstream source for:

* `apps/agent-control-plane-source`
* `apps/agent-control-plane` via the private `CONTROL_PLANE_SOURCE` service binding

Related internal admin routes:

* `POST /v1/admin/control-plane/workflow-monitors/due`
* `POST /v1/admin/control-plane/workflow-monitors/tick`
