Skip to main content
Staffify Docs
Updated

POST /search

An expressive filter grammar across 5 core resources — contacts, companies, deals, invoices and workorders. The grammar follows the HubSpot pattern: filterGroups are OR'd together, filters inside a group are AND'd.

Endpoints

PathRequired scope
POST /contacts/searchcrm.contacts.read
POST /companies/searchcrm.companies.read
POST /deals/searchcrm.deals.read
POST /invoices/searchsales.invoices.read
POST /workorders/searchoperations.workorders.read

Request body

  • filterGroups — up to 3 groups. Filters OR'd between groups, AND'd within.
  • sorts — up to 3 sort keys. Default is created_at DESC, id DESC.
  • query — optional full-text LIKE across the resource's search_blob (contacts/companies/deals) or fallback columns (invoices/workorders).
  • limit — default 50, max 200.
  • starting_after — cursor from next_cursor on previous page.
  • Max 10 filters total across all groups. Max 100 values in IN/NIN.
curl -X POST https://app.staffifyai.com/api/workspace/v1/contacts/search \
  -H "Authorization: Bearer $STAFFIFY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [
      {
        "filters": [
          { "property": "email", "operator": "CONTAINS", "value": "@acme.nl" },
          { "property": "created_at", "operator": "GTE", "value": "2026-01-01" }
        ]
      },
      {
        "filters": [
          { "property": "lifecycle_stage", "operator": "EQ", "value": "customer" }
        ]
      }
    ],
    "sorts": [
      { "property": "created_at", "direction": "DESC" }
    ],
    "query": "jan",
    "limit": 100
  }'

Operators

OperatorDescription
EQEquals. value is a scalar.
NEQNot equals.
GTGreater than.
GTEGreater than or equal.
LTLess than.
LTELess than or equal.
INIn list. values is an array (max 100).
NINNot in list. values is an array (max 100).
CONTAINSSubstring match (strings only).
STARTS_WITHPrefix match (strings only).
BETWEENRange. value is a 2-element array: [from, to].
HAS_PROPERTYColumn IS NOT NULL. No value.
NOT_HAS_PROPERTYColumn IS NULL. No value.

Response

{
  "object": "list",
  "data": [ /* ...resource objects... */ ],
  "has_more": true,
  "next_cursor": "7823",
  "meta": { "request_id": "req_abc123" }
}

Searchable properties

Only these property names are accepted. Unknown properties return 422 UNKNOWN_PROPERTY. This is a defense-in-depth guard against SQL injection — client input never becomes raw SQL.

POST /contacts/search
id, first_name, last_name, email, phone, external_id, crm_company_id, lifecycle_stage, is_archived, do_not_call, vat_number, registration_number, country, job_title, created_at, updated_at
POST /companies/search
id, name, external_id, vat_number, registration_number, website, industry, size, city, postcode, country, phone, email, owner_user_id, annual_revenue, is_archived, created_at, updated_at
POST /deals/search
id, name, value, currency, pipeline_id, stage, probability, close_date, crm_contact_id, crm_company_id, owner_user_id, created_at, updated_at
POST /invoices/search
id, invoice_number, status, crm_contact_id, crm_deal_id, total_amount, currency, due_date, sent_at, paid_at, reference, created_at, updated_at
POST /workorders/search
id, workorder_number, status, workorder_type, priority, assigned_team_member_id, crm_contact_id, hub_customer_id, installation_id, scheduled_at, reported_at, completed_at, signed_at, created_at, updated_at

Errors

  • 422 UNKNOWN_PROPERTY — property is not in the whitelist for this resource.
  • 422 INVALID_VALUE — value is wrong type (e.g. non-numeric for number property) or invalid enum.
  • 422 INVALID_OPERATOR — operator is incompatible (e.g. CONTAINS on a number property).
  • 400 VALIDATION_FAILED — zod violated max limits (filters, groups, sorts, values).
POST /search - Workspace API - Staffify