# Query records



**Endpoint:** `POST /v2/prism/{teamId}/{objectType}/query`  
**Operation ID:** `query`  
**Server:** `https://developers.micro.so`  
**Security:** `[{"apiKey":[]}]`

## Parameters

```json
[
  {
    "name": "teamId",
    "in": "path",
    "required": true,
    "schema": {
      "type": "string",
      "format": "uuid"
    }
  },
  {
    "name": "objectType",
    "in": "path",
    "required": true,
    "schema": {
      "$ref": "#/components/schemas/ObjectType"
    },
    "description": "Queryable object type. Same set as `ObjectType` (CRUD). `GET /v2/prism/{teamId}/properties` also returns metadata for pipeline-owned types such as `message` that are not in this set and cannot be queried. Contacts expose `last_email` as a `ref_message`; you cannot follow it with a `message` query."
  },
  {
    "$ref": "#/components/parameters/IdempotencyKey"
  }
]
```

## Request body

```json
{
  "required": true,
  "content": {
    "application/json": {
      "schema": {
        "type": "object",
        "required": [
          "query"
        ],
        "properties": {
          "query": {
            "type": "object",
            "required": [
              "select"
            ],
            "properties": {
              "select": {
                "type": "array",
                "minItems": 1,
                "items": {
                  "type": "string"
                },
                "description": "Property slugs to select. Use dot notation for relationships (e.g. attendee.contact.first_name). `id` is always returned at the top level of each row and does not need to be selected."
              },
              "filter": {
                "type": "array",
                "items": {
                  "type": "object",
                  "minProperties": 1,
                  "maxProperties": 1,
                  "additionalProperties": {
                    "type": "object",
                    "minProperties": 1,
                    "maxProperties": 1,
                    "propertyNames": {
                      "enum": [
                        "=",
                        "!=",
                        "<",
                        ">",
                        "<=",
                        ">=",
                        "contains",
                        "begins_with",
                        "ends_with",
                        "not_contains",
                        "exists",
                        "not_exists",
                        "is_null",
                        "is_not_null",
                        "between",
                        "in",
                        "not_in"
                      ],
                      "description": "`between` takes a two-element [min, max] array (inclusive on both ends). `is_null` / `is_not_null` are aliases for `not_exists` / `exists` and take any truthy value."
                    },
                    "additionalProperties": {
                      "oneOf": [
                        {
                          "type": "string"
                        },
                        {
                          "type": "boolean"
                        },
                        {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        }
                      ]
                    }
                  }
                },
                "description": "Filters as [{ slug: { operator: value } }]. For select/multiselect properties, values may be option slugs or option UUIDs."
              },
              "sort": {
                "type": "array",
                "items": {
                  "type": "object",
                  "minProperties": 1,
                  "maxProperties": 1,
                  "additionalProperties": {
                    "type": "string",
                    "enum": [
                      "asc",
                      "desc"
                    ]
                  }
                },
                "description": "Sort order as [{ slug: direction }]. Array order determines sort priority"
              },
              "combinator": {
                "type": "string",
                "description": "Logical operator for combining filters",
                "enum": [
                  "AND",
                  "OR"
                ],
                "default": "AND"
              },
              "list_id": {
                "type": "string",
                "format": "uuid"
              },
              "cursor": {
                "type": "string",
                "description": "Opaque cursor from a previous response's `next_cursor`. Pass it back unchanged to fetch the next page. When set, `page` and `limit` are derived from the cursor and any explicit values are ignored."
              },
              "page": {
                "type": "integer",
                "deprecated": true,
                "description": "Page number (1-based). Prefer `cursor`. Page-number pagination drifts under concurrent writes; use it only for one-shot exports."
              },
              "limit": {
                "type": "integer",
                "minimum": 1,
                "maximum": 50,
                "description": "Maximum number of rows to return. Capped server-side at 50; requests above the cap are rejected."
              }
            },
            "additionalProperties": false
          },
          "cursor": {
            "type": "string",
            "description": "Alternative location for the opaque cursor (a sibling of `query`). Use whichever feels more natural; if both are present, `query.cursor` wins."
          },
          "include_total": {
            "type": "boolean",
            "description": "When true, the response includes a `total` field with the unpaginated row count. Costs an additional pass over the result set — for unfiltered totals prefer `GET /v2/prism/{teamId}/{objectType}/count` instead.",
            "default": false
          },
          "id": {
            "oneOf": [
              {
                "type": "string",
                "format": "uuid"
              },
              {
                "type": "array",
                "items": {
                  "type": "string",
                  "format": "uuid"
                }
              }
            ]
          },
          "deleted": {
            "type": "boolean"
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "boxes": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "examples": {
        "contact": {
          "summary": "Contact example",
          "value": {
            "query": {
              "select": [
                "full_name",
                "email",
                "title",
                "organization"
              ],
              "filter": [
                {
                  "full_name": {
                    "=": "Sarah Chen"
                  }
                }
              ],
              "limit": 10
            },
            "include_total": true
          }
        }
      }
    }
  }
}
```

## Responses

```json
{
  "200": {
    "description": "Successful query",
    "headers": {
      "x-request-id": {
        "$ref": "#/components/headers/XRequestId"
      }
    },
    "content": {
      "application/json": {
        "schema": {
          "type": "object",
          "required": [
            "data",
            "has_more"
          ],
          "properties": {
            "data": {
              "type": "array",
              "items": {
                "$ref": "#/components/schemas/PrismQueryRow"
              }
            },
            "has_more": {
              "type": "boolean",
              "description": "Accurate end-of-data signal. False when this page contains the last record; true only when at least one more record exists. (Implementation note: the server fetches one extra row internally to determine this — clients never need to overshoot to discover the end.)"
            },
            "next_cursor": {
              "type": [
                "string",
                "null"
              ],
              "description": "Opaque cursor pointing at the next page. Pass it back unchanged. Do not parse it. The current encoding is offset-based (page + limit), so it has the same concurrent-write drift the deprecated `page` parameter has; treat it as a black box so a future keyset cursor is a drop-in. Null when `has_more` is false."
            },
            "total": {
              "type": [
                "integer",
                "null"
              ],
              "description": "Only populated when the request set `include_total: true`. Total number of records matching the query, ignoring pagination. Opt-in because it costs an additional pass over the result set."
            }
          }
        },
        "examples": {
          "contact": {
            "summary": "Contact example",
            "value": {
              "data": [
                {
                  "id": "11111111-1111-4111-8111-111111111111",
                  "properties": {
                    "full_name": "Sarah Chen",
                    "email": "sarah@example.com",
                    "title": "Partner",
                    "organization": "Acme Ventures"
                  },
                  "is_user_object": false,
                  "source": null
                }
              ],
              "has_more": false,
              "next_cursor": null,
              "total": 1
            }
          }
        }
      }
    }
  },
  "400": {
    "$ref": "#/components/responses/BadRequest"
  },
  "401": {
    "$ref": "#/components/responses/Unauthorized"
  },
  "403": {
    "$ref": "#/components/responses/Forbidden"
  },
  "500": {
    "$ref": "#/components/responses/InternalError"
  }
}
```

## Referenced components

```json
{
  "securitySchemes": {
    "apiKey": {
      "type": "apiKey",
      "in": "header",
      "name": "x-api-key",
      "description": "Public API key generated from Micro settings. Sent as the `x-api-key` header and validated by AWS API Gateway in front of the service."
    }
  },
  "schemas": {
    "ObjectType": {
      "type": "string",
      "description": "Object types that support CRUD, query, list, and per-type property metadata. `GET /v2/prism/{teamId}/properties` (list-all) also returns definitions for pipeline-owned types that are not in this set — including `message`, `thread`, and `linkedin_thread`. Those types are not queryable. Contacts expose `last_email` as a `ref_message`; you cannot query `message` to follow it.",
      "enum": [
        "comment",
        "deal",
        "engagement",
        "identity",
        "ai_chat_thread",
        "ai_chat_message",
        "agent_site",
        "document",
        "action",
        "event",
        "organization",
        "contact"
      ]
    },
    "PrismQueryRow": {
      "type": "object",
      "description": "Row returned by the query endpoint. `id` is always present at the top level. Selected property values are returned under `properties`, keyed by property slug. Reference-typed values are returned as nested `{ id, properties }` objects.",
      "required": [
        "id"
      ],
      "properties": {
        "id": {
          "type": "string",
          "format": "uuid"
        },
        "properties": {
          "type": "object",
          "description": "Selected property values keyed by property slug. For select/multiselect properties, option slugs are returned. For reference properties, values are nested `{ id, properties }` objects.",
          "additionalProperties": {}
        },
        "is_user_object": {
          "type": "boolean"
        },
        "source": {
          "type": [
            "array",
            "null"
          ],
          "items": {
            "type": "string"
          }
        }
      }
    },
    "Error": {
      "type": "object",
      "description": "Canonical JSON error envelope for every non-2xx v2 API response. `error.code` is the machine-readable error code, `error.message` is the human-readable summary, and `error.request_id` identifies the request for support. When supplied, `error.errors` contains field-level validation issues.",
      "required": [
        "error"
      ],
      "properties": {
        "error": {
          "type": "object",
          "required": [
            "code",
            "message",
            "request_id"
          ],
          "properties": {
            "code": {
              "type": "string",
              "description": "Stable machine-readable code. Branch on this, not on the HTTP status, to handle specific failure modes.",
              "example": "invalid_request"
            },
            "message": {
              "type": "string",
              "description": "Human-readable summary suitable for logs. Not localized; do not display verbatim to end users."
            },
            "request_id": {
              "type": [
                "string",
                "null"
              ],
              "description": "Echo of the x-request-id response header. Include in support requests."
            },
            "errors": {
              "type": "array",
              "description": "Optional structured field-level validation issues when the server provides them.",
              "items": {
                "type": "object",
                "properties": {
                  "field": {
                    "type": "string",
                    "description": "JSON path of the offending property (e.g. \".body.default.email\")."
                  },
                  "message": {
                    "type": "string"
                  },
                  "code": {
                    "type": "string",
                    "description": "Validator-specific code (e.g. \"required.openapi.validation\")."
                  }
                },
                "required": [
                  "message"
                ]
              }
            },
            "details": {
              "type": "object",
              "description": "Optional bag of error-specific context. Shape varies by code; clients should treat fields as opaque unless documented."
            }
          }
        }
      }
    }
  },
  "parameters": {
    "IdempotencyKey": {
      "name": "Idempotency-Key",
      "in": "header",
      "required": false,
      "description": "A unique key (UUID or any opaque string up to 255 chars) for an authenticated POST, PUT, or PATCH request. The server retains the initial claim for 24 hours and replays a completed non-5xx response only when the method, path, and request body all match. Reusing a non-expired key with a different method, path, or body returns 409 `idempotency_key_mismatch`; reusing it after expiry returns 409 `idempotency_key_stale`, so use a new key. Replays include the `idempotent-replay: true` response header.",
      "schema": {
        "type": "string",
        "minLength": 1,
        "maxLength": 255
      }
    }
  },
  "headers": {
    "XRequestId": {
      "description": "Correlation ID. Echoed from the request `x-request-id` header when supplied, otherwise generated. Include in support requests.",
      "schema": {
        "type": "string"
      }
    }
  },
  "responses": {
    "BadRequest": {
      "description": "Request validation failed. Inspect `error.errors` for field-level details.",
      "headers": {
        "x-request-id": {
          "$ref": "#/components/headers/XRequestId"
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "Unauthorized": {
      "description": "Missing or invalid credentials. API Gateway maps a missing or invalid `x-api-key` to HTTP 401 with this envelope (including `request_id`). A 403 here means the key was accepted but the caller is not permitted.",
      "headers": {
        "x-request-id": {
          "$ref": "#/components/headers/XRequestId"
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "Forbidden": {
      "description": "Authenticated but not permitted to perform this action.",
      "headers": {
        "x-request-id": {
          "$ref": "#/components/headers/XRequestId"
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    },
    "InternalError": {
      "description": "Unexpected server error. Retry with backoff; report `request_id` if persistent.",
      "headers": {
        "x-request-id": {
          "$ref": "#/components/headers/XRequestId"
        }
      },
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/Error"
          }
        }
      }
    }
  }
}
```
