---
title: "Search data source items"
method: POST
path: "/api/data-source-items/search"
tags: ["data_source_items"]
---

# Search data source items

`POST /api/data-source-items/search`

## Request

- Base URL: `https://beta.getsales.io/playtables/v1`
- URL: `https://beta.getsales.io/playtables/v1/api/data-source-items/search`
- Auth: HTTP bearer and API key in header `Team-SID`

Row-level drill-down behind an import funnel: one row per raw record a data source staged - the untouched payload plus its promotion outcome (status, status_reason, created_object_sid, duplicate_action). Scope data_source_sid + status for "why didn't these rows make it"; q searches the payload (requires data_source_sid); sid.eq resolves people.data_source_item_sid provenance; include data_source = the source; counts.groups.status = the funnel. Totals/metrics → data-sources tools.

Contract:
- MCP tool `search_data_source_items`, registry package `mcp.playtables/data_source_items`, mount `playtables.sources`.
- Operation `search`, response envelope `search`.
- Flags: read only.

## Request body

- SearchDataSourceItemsRequest: Request body of `search_data_source_items`.
  - `filter` object: Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row.
    - `sid` object: Prefix-validated ds_it_ sid(s) - the point-lookup path (no get tool); resolves people.data_source_item_sid provenance backlinks.
      - `eq` string: Item sid (ds_it_…).
      - `in` string[]
    - `data_source_sid` object: The primary review scope - funnel drill-downs always pass the source.
      - `eq` string
      - `in` string[]
    - `status` object: Promotion outcome(s) - in:["failed","duplicate","stoplisted","disqualified"] = "rows that did not make it".
      - `eq` 'pending' | 'promoted' | 'duplicate' | 'stoplisted' | 'disqualified' | 'failed'
      - `ne` 'pending' | 'promoted' | 'duplicate' | 'stoplisted' | 'disqualified' | 'failed'
      - `in` string[]
      - `nin` string[]
    - `created_object_sid` object: Provenance backlink (cr_pp_ or cr_co_ per the source object type); is_null:true = rows that produced nothing.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `q` string: MySQL LIKE (infix) over the raw payload JSON - find one record by any fragment (name, email). Requires data_source_sid (eq or in) in the same filter, else 422 - payload search is per-source.
    - `created_at` object: Ingestion window; ISO 8601 range - combine bounds in one object.
      - `gte` string
      - `lte` string
      - `gt` string
      - `lt` string
    - `updated_at` object: Terminal-transition window ("failures in the last hour").
      - `gte` string
      - `lte` string
      - `gt` string
      - `lt` string
    - `deleted_at` object: Default scope is { is_null: true } (live rows).
      - `gte` string
      - `lte` string
      - `is_null` boolean
  - `include` string[]: Relations to attach to every item; omit for the bare rows.
  - `sort` object: One column and its direction; omit for the default order.
    - `field` 'created_at' | 'updated_at' | 'row_number', required: The column to order by.
    - `direction` 'asc' | 'desc': asc or desc; default desc.
  - `page_size` integer: 0..500, default 50; 0 = counts only, 1 = the first row.
  - `cursor` string, nullable: pagination.next_cursor of the previous page.

## Response `200`

`search` success envelope.

- SearchDataSourceItemsResponse
  - `success` true, required
  - `operation` 'search', required
  - `items` object[], required
    - `item` object, required
      - `sid` string, required: Item sid (ds_it_…).
      - `team_sid` string, required: Owning team (ts_tm_…, external - gs.service.id).
      - `data_source_sid` string, required: ds_sc_… owning source - see ./data_sources.md; set at birth, never re-validated.
      - `row_number` integer, nullable, required: 1-based CSV data-row position (type=csv sources); null for the search kinds and for webhook.
      - `payload` union, required: Raw external record as ingested, never mutated (legacy raw_data). An object for every kind: the collector parser record for a search source, the CSV row keyed by its own header for csv, the selected slice of the body for webhook. Only csv rows staged before 2026-08-04 are positional string arrays.
        - object
        - string[]
      - `status` 'pending' | 'promoted' | 'duplicate' | 'stoplisted' | 'disqualified' | 'failed', required: Promotion outcome - service-managed, never client-writable.
      - `status_reason` string, nullable, required: Human-readable outcome detail (max 2048): failure message or matched stoplist entry; null for pending and clean promoted rows (legacy error_reason).
      - `created_object_sid` string, nullable, required: Created/updated object on promoted, matched object on duplicate - the prefix follows the source object type (cr_pp_ people, cr_co_ companies). Write-once at resolve; may dangle after the object is deleted.
      - `already_in_playtable_sid` string, nullable, required: Duplicate people rows only - pt_tb_… the person's membership at match time; snapshot, never re-validated.
      - `duplicate_action` 'skipped' | 'moved' | 'membership_added' | 'merged' | 'disqualified', nullable, required: Duplicate rows only - what the duplicate policy did; null otherwise (incl. company already a member).
      - `created_at` string, required: ISO 8601 UTC - ingestion time (the "collected" period column).
      - `updated_at` string, required: ISO 8601 UTC - terminal transition time (the funnel period column read by data-sources metrics).
      - `deleted_at` string, nullable, required: ISO 8601 UTC - set only by the source cascade delete; null = live. Terminal rows hard-purge 90 days after updated_at.
    - `included` object, required
      - `data_source` object: DataSourceDomain row (ds_sc_…) - the owning source - see ./data_sources.md; present when requested.
        - `sid` string, required
  - `pagination` object, required
    - `next_cursor` string, nullable, required
    - `has_more` boolean, required
    - `total_count` integer, nullable, required
  - `applied_filters` object, required
  - `includes` string[], required
  - `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.
  - `counts` object
    - `total_count` integer, required: Rows matching the filter (full filter scope, not the page).
    - `groups` object, required: The distribution axes (§4.17); PHP empty map serialises as [].
      - `status` union, required: Flat {value: count} per DataSourceItemStatusEnum value present in scope - the import funnel.
        - object
        - unknown[]
          - unknown
      - `duplicate_action` union: The duplicate rows by what the policy did (DataSourceItemDuplicateAction → count), 2026-10-28: the rows keep status duplicate, so read the people moved into the table (moved) as imported and the rest as duplicates still standing. Empty when there are none.
        - object
        - unknown[]
          - unknown
      - `already_in_playtable_sid` union: The duplicate people the policy left where they were (status duplicate, duplicate_action skipped), by the table they are in (pt_tb_… → count): what move_data_source_duplicates would move (2026-10-28). Empty when there are none.
        - object
        - unknown[]
          - unknown

## 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)
