---
title: "Search Purchase Orders"
method: POST
path: "/api/internal/purchase-orders/search"
tags: ["Purchase Orders"]
---

# Search Purchase Orders

`POST /api/internal/purchase-orders/search`

Search purchase orders for an institution.

The ``query`` field accepts a Postgres tsquery expression — see the
PurchaseOrderSearchFilters docstring for syntax and examples. Malformed
tsquery returns 400 with the Postgres syntax error.

All filters compose with AND: matching POs must satisfy every supplied
filter (institution_ids, query, amount range, date range).

At least one of ``institution_ids`` or ``query`` must be supplied —
unbounded scans of the 235M-row PO table are rejected.

## Request body

- PurchaseOrderSearchFilters — Search filters for purchase orders. The ``query`` field accepts a Postgres tsquery expression evaluated against the ``search_vector`` column (which covers both supplier_name and item_description, tokenized with the ``simple`` config — no stemming, no stop-word filtering, automatic word-boundary matching). Operators: & (AND), | (OR), ! (NOT), parens for grouping Tokens with multiple words must be combined explicitly — there's no implicit AND. Hyphenated words tokenize both as the full string and the parts (CDW-G becomes cdw-g, cdw, g — any of those will match). Examples: "lightspeed" Match the word lightspeed in either field. "lightspeed & systems" Both words must appear (any order, either field). "lightspeed | securly | goguardian" Any of the three. "(lightspeed | securly) & !pos & !demo" Either competitor, but exclude POS systems and demo POs. "((cdw & cisco) | (amazon & networking)) & 2026" Reseller-aware nested query. Malformed queries return HTTP 400 with the Postgres syntax error. At least one of ``institution_ids`` or ``query`` must be supplied — the endpoint rejects requests with both empty to prevent unbounded scans.
  - `institution_ids` string[], nullable
  - `query` string, nullable
  - `states` string[], nullable
  - `source_tables` string[], nullable
  - `min_amount` number, nullable
  - `max_amount` number, nullable
  - `start_date` string, date, nullable
  - `end_date` string, date, nullable
  - `sort` 'po_date_desc' | 'amount_desc'
  - `offset` integer
  - `limit` integer

## Response `200`

Successful Response

- PaginatedResponsePurchaseOrderResponse
  - `results` PurchaseOrderResponse[], required
    - `id` string, required
    - `institution_id` string, nullable
    - `entity_name` string, nullable
    - `source_table` string, nullable
    - `supplier_name` string, nullable
    - `item_description` string, nullable
    - `total_amount` number, nullable
    - `po_date` string, date, nullable
    - `po_id` string, nullable
    - `institution_name` string, nullable
    - `institution_state` string, nullable
  - `total` integer, required
  - `offset` integer, required
  - `limit` integer, required

## Other responses

- `422` — Validation Error

---

[API](https://skmtc.net/nationgraph/apis/nationgraph-api.md) · [All operations](https://skmtc.net/nationgraph/apis/nationgraph-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/nationgraph/nationgraph-api/revisions/85804e68d86d/schema)
