SocialCrawl Cohorts API

Cohorts - tenant-private panels of public social identities with asynchronous keyword queries

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/socialcrawl-cohorts-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no email required.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

socialcrawl-cohorts-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: SocialCrawl Cohorts API
  version: 1.0.0
  description: 'Unified social media data API - one API key, one consistent response format, 50 platforms, 400 endpoints. Power AI agents with clean social data.


    Slim variant: inline examples removed and the shared error responses hoisted into components. The full annotated spec is at https://www.socialcrawl.dev/openapi.json.'
  contact:
    name: SocialCrawl
    url: https://www.socialcrawl.dev
    email: support@socialcrawl.dev
servers:
- url: https://www.socialcrawl.dev/v1
  description: Production
security:
- ApiKeyAuth: []
tags:
- description: Cohorts - tenant-private panels of public social identities with asynchronous keyword queries
  name: cohorts
paths:
  /cohort-queries/{queryId}:
    delete:
      description: Cancels a cohort query. Queued work never starts and running work stops at the next page boundary. Pages already fetched stay billable; the unspent reservation is refunded exactly once.
      operationId: cohorts_cancel_query
      parameters:
      - description: Cohort query identifier returned by `POST /v1/cohorts/{cohortId}/queries`.
        in: path
        name: queryId
        required: true
        schema:
          type: string
      responses:
        '204':
          description: Cancelled. No response body.
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Cancel a cohort query
      tags:
      - cohorts
      x-credit-cost: 0
    get:
      description: Returns status, durable progress counters, and billing for a cohort query. A query can be `succeeded` with partial failures - read `progress.pages_failed` and per-member `coverage` before treating a result set as exhaustive.
      operationId: cohorts_get_query
      parameters:
      - description: Cohort query identifier returned by `POST /v1/cohorts/{cohortId}/queries`.
        in: path
        name: queryId
        required: true
        schema:
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  cached:
                    type: boolean
                  credits_remaining:
                    type:
                    - integer
                    - 'null'
                  credits_used:
                    type: integer
                  data:
                    properties:
                      actual_credits:
                        description: Credits actually charged, metered one per successful upstream page.
                        type: integer
                      cohort_id:
                        type: string
                      completed_shard_count:
                        type: integer
                      failed_shard_count:
                        type: integer
                      id:
                        type: string
                      max_credits:
                        type: integer
                      member_count:
                        type: integer
                      progress:
                        properties:
                          matches:
                            type: integer
                          members_completed:
                            type: integer
                          members_total:
                            type: integer
                          pages_failed:
                            type: integer
                          pages_succeeded:
                            type: integer
                          routes_completed:
                            type: integer
                          routes_planned:
                            type: integer
                          shards_completed:
                            type: integer
                          shards_failed:
                            type: integer
                          shards_total:
                            type: integer
                        type: object
                      refunded_credits:
                        description: Unspent portion of the reservation, refunded exactly once.
                        type: integer
                      reserved_credits:
                        description: 'Worst-case ceiling reserved at submission: sum over members of (route page cap x credits per page). Single-page platforms (twitter, bluesky, threads, twitch) count exactly one page regardless of max_pages_per_identity.'
                        type: integer
                      result_count:
                        type: integer
                      shard_count:
                        type: integer
                      status:
                        enum:
                        - queued
                        - running
                        - succeeded
                        - failed
                        - cancelled
                        - expired
                        type: string
                    type: object
                  endpoint:
                    type: string
                  platform:
                    type: string
                  request_id:
                    type: string
                  success:
                    type: boolean
                type: object
          description: Cohort query status
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Check cohort query status
      tags:
      - cohorts
      x-credit-cost: 0
  /cohort-queries/{queryId}/results:
    get:
      description: 'Returns cursor-paginated keyword matches plus per-member coverage. Matching is deterministic: Unicode NFKC normalization, locale-independent case folding, whitespace collapse, then whole-word matching at Unicode word boundaries (`acme` matches `#acme` but not `acmecorp`; scripts without word delimiters, such as CJK, effectively require exact token matches). Matched keywords are echoed in their normalized form. On YouTube and Twitch the matched text covers the title and the description. No stemming, fuzzy matching, or semantic expansion. The response carries the standard `pagination` block (send `pagination.next_cursor` back as `cursor`) and a `dropped` counter, and the raw `data.next_cursor` is accepted as well.'
      operationId: cohorts_list_results
      parameters:
      - description: Cohort query identifier returned by `POST /v1/cohorts/{cohortId}/queries`.
        in: path
        name: queryId
        required: true
        schema:
          type: string
      - description: Opaque cursor from a previous `next_cursor`.
        in: query
        name: cursor
        required: false
        schema:
          type: string
      - description: Page size. Defaults to 100, capped at 500.
        in: query
        name: limit
        required: false
        schema:
          default: 100
          maximum: 500
          minimum: 1
          type: integer
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  cached:
                    type: boolean
                  credits_remaining:
                    type:
                    - integer
                    - 'null'
                  credits_used:
                    type: integer
                  data:
                    properties:
                      coverage:
                        description: One record per cohort member, whether or not it matched. `window_complete` is true only when the route reached the requested time boundary or an end-of-feed marker; a page budget, timeout, or error leaves it false.
                        items:
                          properties:
                            external_id:
                              type:
                              - string
                              - 'null'
                            member_id:
                              type: string
                            oldest_seen:
                              format: date-time
                              type:
                              - string
                              - 'null'
                            pages:
                              type: integer
                            platform:
                              type: string
                            query_id:
                              type: string
                            route_errors:
                              items:
                                properties:
                                  code:
                                    type: string
                                  route:
                                    type: string
                                type: object
                              type: array
                            status:
                              enum:
                              - complete
                              - partial
                              - not_found
                              - unsupported
                              - failed
                              type: string
                            window_complete:
                              type: boolean
                          type: object
                        type: array
                      items:
                        items:
                          properties:
                            canonical_url:
                              type:
                              - string
                              - 'null'
                            content_id:
                              type: string
                            external_id:
                              description: Your own opaque identifier for this panel member.
                              type:
                              - string
                              - 'null'
                            matched_keywords:
                              items:
                                type: string
                              type: array
                            member_id:
                              type: string
                            platform:
                              type: string
                            published_at:
                              format: date-time
                              type: string
                            query_id:
                              type: string
                            retrieved_at:
                              format: date-time
                              type: string
                            route:
                              type: string
                            text_excerpt:
                              type: string
                          type: object
                        type: array
                      next_cursor:
                        description: Opaque signed cursor for the next page, or null on the last page. Pages are additionally bounded so the serialized body never exceeds 1 MB.
                        type:
                        - string
                        - 'null'
                    type: object
                  endpoint:
                    type: string
                  platform:
                    type: string
                  request_id:
                    type: string
                  success:
                    type: boolean
                type: object
          description: Cohort query results page
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Read cohort query results
      tags:
      - cohorts
      x-credit-cost: 0
  /cohorts:
    post:
      description: Creates an empty cohort. Uploading members or submitting a query renews the expiry using the configured retention period.
      operationId: cohorts_create
      parameters:
      - description: Required UUID that makes the mutation safely retriable. Replaying the same key with the same body returns the original resource with the X-Idempotent-Replay header; replaying it with a different body returns 422 IDEMPOTENCY_KEY_PAYLOAD_MISMATCH.
        in: header
        name: Idempotency-Key
        required: true
        schema:
          format: uuid
          type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                name:
                  description: Optional label, up to 120 characters.
                  type: string
                retention_days:
                  default: 30
                  description: How long cohort membership is retained before automatic purge.
                  maximum: 90
                  minimum: 7
                  type: integer
              type: object
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                properties:
                  cached:
                    type: boolean
                  credits_remaining:
                    type:
                    - integer
                    - 'null'
                  credits_used:
                    type: integer
                  data:
                    properties:
                      created_at:
                        format: date-time
                        type: string
                      expires_at:
                        format: date-time
                        type: string
                      id:
                        type: string
                      member_count:
                        type: integer
                      name:
                        type:
                        - string
                        - 'null'
                      retention_days:
                        type: integer
                      updated_at:
                        format: date-time
                        type: string
                    type: object
                  endpoint:
                    type: string
                  platform:
                    type: string
                  request_id:
                    type: string
                  success:
                    type: boolean
                type: object
          description: Cohort created
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Create a cohort
      tags:
      - cohorts
      x-credit-cost: 0
  /cohorts/{cohortId}:
    delete:
      description: Deletes the cohort and cascades its members, queries, shards, and results. Active queries are marked cancelled. Immutable credit-ledger receipts are never deleted.
      operationId: cohorts_delete
      parameters:
      - description: Cohort identifier returned by `POST /v1/cohorts`.
        in: path
        name: cohortId
        required: true
        schema:
          type: string
      responses:
        '204':
          description: Deleted. No response body.
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Delete a cohort
      tags:
      - cohorts
      x-credit-cost: 0
    get:
      description: Returns cohort metadata and counts. It never enumerates or reveals stored identities - the identities you uploaded are encrypted at rest and are not readable back through the API.
      operationId: cohorts_get
      parameters:
      - description: Cohort identifier returned by `POST /v1/cohorts`.
        in: path
        name: cohortId
        required: true
        schema:
          type: string
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  cached:
                    type: boolean
                  credits_remaining:
                    type:
                    - integer
                    - 'null'
                  credits_used:
                    type: integer
                  data:
                    properties:
                      created_at:
                        format: date-time
                        type: string
                      expires_at:
                        format: date-time
                        type: string
                      id:
                        type: string
                      member_count:
                        type: integer
                      name:
                        type:
                        - string
                        - 'null'
                      retention_days:
                        type: integer
                      updated_at:
                        format: date-time
                        type: string
                    type: object
                  endpoint:
                    type: string
                  platform:
                    type: string
                  request_id:
                    type: string
                  success:
                    type: boolean
                type: object
          description: Cohort metadata
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Get a cohort
      tags:
      - cohorts
      x-credit-cost: 0
  /cohorts/{cohortId}/members:
    put:
      description: 'Upserts one chunk of 1-1,000 members; a cohort holds at most 10,000. Re-sending the same `external_id` updates its identity without growing the count. Supported platforms: bluesky, instagram, kwai, linkedin, threads, tiktok, truth-social, twitch, twitter, youtube.'
      operationId: cohorts_upsert_members
      parameters:
      - description: Cohort identifier returned by `POST /v1/cohorts`.
        in: path
        name: cohortId
        required: true
        schema:
          type: string
      - description: Required UUID that makes the mutation safely retriable. Replaying the same key with the same body returns the original resource with the X-Idempotent-Replay header; replaying it with a different body returns 422 IDEMPOTENCY_KEY_PAYLOAD_MISMATCH.
        in: header
        name: Idempotency-Key
        required: true
        schema:
          format: uuid
          type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                members:
                  items:
                    properties:
                      external_id:
                        description: Your own opaque identifier, echoed back on every match and coverage record. Never sent upstream.
                        type: string
                      handle:
                        description: Public handle, profile URL, or channel ID for this platform.
                        type: string
                      platform:
                        enum:
                        - bluesky
                        - instagram
                        - kwai
                        - linkedin
                        - threads
                        - tiktok
                        - truth-social
                        - twitch
                        - twitter
                        - youtube
                        type: string
                    required:
                    - handle
                    - platform
                    type: object
                  maxItems: 1000
                  minItems: 1
                  type: array
              required:
              - members
              type: object
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                properties:
                  cached:
                    type: boolean
                  credits_remaining:
                    type:
                    - integer
                    - 'null'
                  credits_used:
                    type: integer
                  data:
                    properties:
                      inserted:
                        type: integer
                      member_count:
                        type: integer
                      unchanged:
                        type: integer
                      updated:
                        type: integer
                    type: object
                  endpoint:
                    type: string
                  platform:
                    type: string
                  request_id:
                    type: string
                  success:
                    type: boolean
                type: object
          description: Member upload applied
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Upload cohort members
      tags:
      - cohorts
      x-credit-cost: 0
  /cohorts/{cohortId}/queries:
    post:
      description: Submits an asynchronous keyword query over the cohort's recent authored activity. Returns 202 immediately with a poll URL. Credits are reserved at the worst-case ceiling on submission, metered one per successful upstream page, and the unspent remainder is refunded exactly once when the query reaches a terminal state.
      operationId: cohorts_create_query
      parameters:
      - description: Cohort identifier returned by `POST /v1/cohorts`.
        in: path
        name: cohortId
        required: true
        schema:
          type: string
      - description: Required UUID that makes the mutation safely retriable. Replaying the same key with the same body returns the original resource with the X-Idempotent-Replay header; replaying it with a different body returns 422 IDEMPOTENCY_KEY_PAYLOAD_MISMATCH.
        in: header
        name: Idempotency-Key
        required: true
        schema:
          format: uuid
          type: string
      requestBody:
        content:
          application/json:
            schema:
              properties:
                date_from:
                  description: Start of the observation window as a full RFC3339 timestamp.
                  format: date-time
                  type: string
                date_to:
                  description: Optional end of the observation window.
                  format: date-time
                  type: string
                keywords:
                  description: 1-20 unique keywords, matched literally after Unicode normalization and case folding.
                  items:
                    type: string
                  maxItems: 20
                  minItems: 1
                  type: array
                max_credits:
                  description: Your safety limit. Submission fails with 400 if the computed ceiling exceeds it; it is never permission to exceed the ceiling.
                  type: integer
                max_items_per_identity:
                  maximum: 1000
                  minimum: 1
                  type: integer
                max_pages_per_identity:
                  description: Page budget per route. Exhausting it leaves `window_complete` false for that member.
                  maximum: 20
                  minimum: 1
                  type: integer
                platforms:
                  description: Optional subset of the cohort's platforms to query. Defaults to every platform present in the cohort.
                  items:
                    enum:
                    - bluesky
                    - instagram
                    - kwai
                    - linkedin
                    - threads
                    - tiktok
                    - truth-social
                    - twitch
                    - twitter
                    - youtube
                    type: string
                  type: array
              required:
              - date_from
              - keywords
              - max_credits
              - max_items_per_identity
              - max_pages_per_identity
              type: object
        required: true
      responses:
        '202':
          content:
            application/json:
              schema:
                properties:
                  cached:
                    type: boolean
                  credits_remaining:
                    type:
                    - integer
                    - 'null'
                  credits_used:
                    type: integer
                  data:
                    properties:
                      estimated_credits:
                        type: integer
                      member_count:
                        type: integer
                      progress:
                        properties:
                          matches:
                            type: integer
                          members_completed:
                            type: integer
                          members_total:
                            type: integer
                          pages_failed:
                            type: integer
                          pages_succeeded:
                            type: integer
                          routes_completed:
                            type: integer
                          routes_planned:
                            type: integer
                          shards_completed:
                            type: integer
                          shards_failed:
                            type: integer
                          shards_total:
                            type: integer
                        type: object
                      query_id:
                        type: string
                      replayed:
                        description: True when this 202 replays an earlier submission via the same Idempotency-Key; the envelope also carries idempotent_replay and the X-Idempotent-Replay response header. A replay reports the query's CURRENT state, not necessarily queued.
                        type: boolean
                      reserved_credits:
                        type: integer
                      result_url:
                        type: string
                      shard_count:
                        type: integer
                      status:
                        enum:
                        - queued
                        - running
                        - succeeded
                        - failed
                        - cancelled
                        - expired
                        type: string
                      status_url:
                        type: string
                    type: object
                  endpoint:
                    type: string
                  platform:
                    type: string
                  request_id:
                    type: string
                  success:
                    type: boolean
                type: object
          description: Query accepted
        '400':
          $ref: '#/components/responses/Error400'
        '401':
          $ref: '#/components/responses/Error401'
        '402':
          $ref: '#/components/responses/Error402'
        '404':
          $ref: '#/components/responses/Error404'
        '405':
          $ref: '#/components/responses/Error405'
        '409':
          $ref: '#/components/responses/Error409'
        '413':
          $ref: '#/components/responses/Error413'
        '422':
          $ref: '#/components/responses/Error422'
        '429':
          $ref: '#/components/responses/Error429'
        '500':
          $ref: '#/components/responses/Error500'
      security:
      - ApiKeyAuth: []
      summary: Submit a cohort keyword query
      tags:
      - cohorts
components:
  responses:
    Error429:
      description: 'Rate or concurrency limit exceeded. `RATE_LIMITED`: more than 600 requests in a 1-minute sliding window on this API key (headers `X-RateLimit-Limit`/`Remaining`/`Reset`; `Retry-After` is seconds until the window resets). `CONCURRENCY_LIMIT`: more than 50 simultaneous in-flight requests (headers `X-Concurrency-Limit`/`Remaining`; short static `Retry-After`). Both are unbilled. Honor `Retry-After`, then back off with jitter. See /docs/rate-limits.'
      x-error-codes:
      - RATE_LIMITED
      - CONCURRENCY_LIMIT
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Error401:
      description: Unauthorized - missing or invalid API key
      x-error-codes:
      - MISSING_API_KEY
      - INVALID_API_KEY
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Error402:
      description: Payment required - the account balance is too low, or the calling key has spent its own per-key credit limit
      x-error-codes:
      - INSUFFICIENT_CREDITS
      - KEY_BUDGET_EXCEEDED
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Error500:
      description: Internal server error - credits automatically refunded
      x-error-codes:
      - INTERNAL_ERROR
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Error400:
      description: Invalid reques

# --- truncated at 32 KB (38 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/socialcrawl/refs/heads/main/openapi/socialcrawl-cohorts-api-openapi.yml