---
title: "Pipeline stages metrics"
method: POST
path: "/api/pipeline-stages/metrics"
tags: ["pipeline_stages"]
---

# Pipeline stages metrics

`POST /api/pipeline-stages/metrics`

## Request

- Base URL: `https://beta.getsales.io/playtables/v1`
- URL: `https://beta.getsales.io/playtables/v1/api/pipeline-stages/metrics`
- Auth: HTTP bearer and API key in header `Team-SID`

The funnel for one pipeline: per stage, how many objects sit in it now, plus summed deal_size for object:"company". metrics is keyed by stage sid with a "null" entry for the objects in no stage; an empty stage is absent, not zero, and names come from search_pipeline_stages. No period: point-in-time, not a windowed rate. filter is a PEOPLE or COMPANY filter (the shape search_people / search_companies take), never a stage filter. Reads Elasticsearch: a listing number, never a billing one.

Contract:
- MCP tool `get_pipeline_stages_metrics`, registry package `mcp.playtables/pipeline_stages`, mount `playtables.pipeline`.
- Operation `metrics`, response envelope `metrics`.
- Flags: read only.

## Request body

- GetPipelineStagesMetricsRequest: Request body of `get_pipeline_stages_metrics`.
  - `object` 'person' | 'company', required: Which funnel to count: person (over the people index) or company (over the companies index, which is also what enables deal_sum).
  - `filter` object: Optional scope: a people filter when object is person, a company filter when it is company (operator objects as on the search tools, e.g. {playtable_sid: {eq: pt_tb_...}}). Omitted = the whole team. deleted_at is ignored: the funnel counts live rows only.

## Response `200`

`metrics` success envelope.

- GetPipelineStagesMetricsResponse
  - `success` true, required
  - `operation` 'metrics', required
  - `metrics` object, required: Keyed by stage sid (cr_ps_…), plus a "null" key carrying the objects with no stage. A stage with no objects is absent from the map, not a zero row.
  - `applied_filters` object
  - `meta` object, required
    - `trace_id` string, required: UUID v7; same 128-bit value as the X-Trace-Id header.
    - `span_id` string, required: 16 hex chars, root span of this request.
    - `timestamp` string, required: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
    - `duration_ms` integer, required: Server-side wall clock.
    - `team_sid` string, nullable: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
    - `actor_type` string, nullable: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
  - `categories` object, required: The same counts folded per category, every one of the seven present (0 when empty); the "null" bucket folds into none. Read this for "how many are approaching": never fold the stage map yourself.
    - `cold` integer
    - `approaching` integer
    - `engaging` integer
    - `positive` integer
    - `nurture` integer
    - `negative` integer
    - `disqualified` integer

## Other responses

- `4XX`: MCP error envelope. `error.code` is one of validation_failed, nothing_to_update, not_found, relation_not_found, invalid_transition, limit_exceeded, payment_required, duplicate_rejected, conflict, delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
- `5XX`: MCP error envelope with `error.code` internal_error or service_unavailable.

---

[API](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables.md) - [All operations](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables/llms.txt) - [OpenAPI document](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables/revisions/aa394506515d?raw)
