PSA/docs/api/search.md
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

5.2 KiB
Raw Permalink Blame History

Unified Full-Text Search

The GET /api/v1/search endpoint searches across all indexed business records in a single request, returning results from any combination of tickets, clients, contacts, projects, assets, invoices, contracts, documents, knowledge-base articles, and more — filtered by the caller's permissions and scoped to the caller's tenant.

Before this endpoint, callers had to query each resource's dedicated /search route separately and merge results themselves. The unified endpoint handles that fan-out internally.

Authentication

Include your API key in the x-api-key header. No separate search permission is required — any valid API key may call this endpoint. Client-portal API keys are automatically scoped to their own client's records.

GET /api/v1/search
x-api-key: <your-api-key>

Query parameters

Parameter Required Type Description
query Yes string (1200 chars) Full-text query. Supports OR for alternatives (e.g. laptop OR workstation).
types No string Comma-separated object types to include. Omit to search every type the caller can read. See Supported types.
limit No integer (1100) Maximum results per page. Defaults to 30.
cursor No string Opaque pagination cursor from a prior response's nextCursor.
sort No relevance | recent Ordering. relevance (default) ranks by full-text score; recent orders by last-updated timestamp.

Access control

Results pass two filters before being returned:

  1. Per-type permission gate — Any object type the caller's role cannot read is silently excluded. For example, an API key without invoice:read receives no invoice, invoice item, or invoice annotation results.
  2. Per-row ACL check — Each candidate result is verified against the per-row access-control record in the search index. Only records the user could see in-app are returned.

Response

{
  "data": {
    "results": [
      {
        "type": "ticket",
        "id": "9a4b...",
        "title": "Network outage at main office",
        "subtitle": "Acme Corp · Open",
        "snippet": "...the <mark>router</mark> stopped responding...",
        "url": "/tickets/9a4b...",
        "score": 0.91,
        "updatedAt": "2026-05-28T10:15:00Z"
      }
    ],
    "groups": {
      "ticket": 4,
      "asset": 2
    },
    "totalCount": 6,
    "nextCursor": "eyJ..."
  }
}

Response fields

Field Type Description
results array Matched records for this page, ordered by sort.
results[].type string Object type (e.g. ticket, client, asset).
results[].id string Record identifier within its type.
results[].parentId string? Parent record identifier for nested types (e.g. the ticket ID for a ticket_comment).
results[].title string Primary display label.
results[].subtitle string? Secondary context line.
results[].snippet string? Matched-text excerpt with <mark> tags around highlighted terms.
results[].url string Relative in-app URL for the record.
results[].score number Full-text relevance score; higher is more relevant.
results[].updatedAt string (ISO 8601) Last-updated timestamp of the source record.
groups object Per-type total match counts across all pages.
totalCount integer Total matches across all permitted types.
nextCursor string? Cursor for the next page; absent when all results fit in the current page.

Pagination

The endpoint uses cursor-based pagination. When a response includes nextCursor, pass it as the cursor parameter on the next call with the same query, types, and sort values. The groups and totalCount fields always reflect the full result set, not just the current page.

Rate limiting

Subject to the standard API rate limit: 120-request burst, 60 requests per minute sustained. See API Rate Limiting and Webhooks.

Supported types

Pass any comma-separated subset of these values in the types parameter:

client, contact, user, ticket, ticket_comment, project, project_phase, project_task, project_task_comment, asset, invoice, invoice_item, invoice_annotation, contract, client_contract, document, kb_article, service_catalog, service_request_submission, service_request_definition, workflow_task, interaction, schedule_entry, time_entry, board, category, tag, status

Types the caller's role cannot read are automatically excluded even if listed explicitly.

Examples

Search across all types:

curl "https://algapsa.com/api/v1/search?query=network+outage" \
  -H "x-api-key: $ALGA_API_KEY"

Restrict to tickets and assets, sort by recency:

curl "https://algapsa.com/api/v1/search?query=router&types=ticket,asset&sort=recent&limit=20" \
  -H "x-api-key: $ALGA_API_KEY"

Fetch the next page:

curl "https://algapsa.com/api/v1/search?query=router&types=ticket,asset&sort=recent&limit=20&cursor=$NEXT_CURSOR" \
  -H "x-api-key: $ALGA_API_KEY"