Pulse IntelligenceAPI Docs

Filters

The curated filter vocabulary, operator semantics, and option lookups

Every resource on the public API exposes a deliberately curated set of filterable fields and response columns — not the full internal field set Pulse's own product UI can filter on. This guide is the complete reference: how to discover the vocabulary, every operator and what it does, the full field allowlists for companies and mining-assets, what publications/people search actually accept, and how to resolve select-type values.

Curated vocabulary

Each resource — companies, mining-assets — has its own allowlist of field keys it exposes publicly. A field only becomes available once someone deliberately adds it to that resource's allowlist; new internal fields are excluded by default, not exposed by default. This keeps the public contract stable and avoids leaking user-scoped internal concepts (like a saved company set, which has no meaning for an organization-wide API key) onto the public surface.

publications and people search have no such allowlist — see Publications and people search below for what they actually accept.

If you reference a filter field or request a column outside a resource's curated set, the request fails with a 400:

{
  "error": {
    "code": "unsupported_filter_field",
    "message": "Unknown or unsupported filter field for the public API: 'internal_score'.",
    "field": "internal_score",
    "resource": "companies"
  }
}

The same happens for columns, with unsupported_column as the code instead.

Discovering fields

GET /v1/filters/{resource}/

Call this endpoint to get the current filterable fields and available columns for a resource — the same set that resource's /search endpoint will accept. resource is one of companies or mining-assets.

curl https://api.pulseintelligence.com/v1/filters/companies/ \
  -H "Authorization: Bearer pulse_a1b2c3d4_<secret>"

A truncated response for companies looks like:

{
  "resource": "companies",
  "filters": [
    {
      "field": "market_cap_in_usd",
      "operators": ["gte", "lte"],
      "type": "number",
      "unit": "USD",
      "options_endpoint": null,
      "label": "Market Cap"
    },
    {
      "field": "commodities",
      "operators": ["has_any", "has_only"],
      "type": "select",
      "unit": null,
      "options_endpoint": "/commodities/options/",
      "label": "Primary commodities"
    }
  ],
  "columns": [
    { "key": "market_cap_in_usd", "title": "Market Cap", "type": "number", "sortable": true },
    { "key": "commodities", "title": "Primary Commodities", "type": null, "sortable": false }
  ]
}

Per filter entry:

  • field — the key to use in a search filters clause.
  • operators — the operators valid for this field.
  • type — the field's value type (number, select, date, etc.).
  • unit — the unit a numeric threshold should be expressed in, when applicable (e.g. "USD"), otherwise null.
  • options_endpoint — for select-type fields, the path to resolve valid values against GET /v1/options/{path}/ (see Resolving option values below); null for fields that don't need option resolution.
  • label — a human-readable label for the field.

An unsupported resource returns a 400:

{
  "error": {
    "code": "invalid_argument",
    "message": "Unsupported resource 'listings'. Available in the public API: ['companies', 'mining-assets'].",
    "resource": "listings"
  }
}

Operator semantics

The shared filter engine (pulse_table) defines a larger operator set, but the public API's curated fields only ever advertise these four — every operators array you'll see from GET /v1/filters/{resource}/ is a subset of this list:

OperatorField typesValue shapeMeaning
gtenumber, datea single number, or an ISO date stringField ≥ value.
ltenumber, datea single number, or an ISO date stringField ≤ value.
has_anyselectnon-empty list of option idsMatch if the field's value (or, for a multi-value field, any of its values) is in the given list — an OR match.
has_onlyselectnon-empty list of option idsExact-set match: matches only rows with no qualifying value outside the given list — the complement of has_any. Every has_only field in the tables below (exchanges, commodities, all_commodities, asset_phases, asset_stages on companies; commodities, exchanges on mining assets) implements this exact-set semantic.

No public field uses eq, ne, gt, lt, exact, contains, or range — those exist in pulse_table for internal product filters but aren't reachable through any field in either resource's curated allowlist.

A gte/lte pair on the same field is how you express a numeric or date range (there's no separate range operator on the public surface):

{
  "filters": [
    { "field": "market_cap_in_usd", "operator": "gte", "value": 100000000 },
    { "field": "market_cap_in_usd", "operator": "lte", "value": 500000000 }
  ]
}

Building a search payload

The search endpoints (POST /v1/companies/search/, POST /v1/mining-assets/search/) take three parts:

  • filters — a list of clauses: {"field": "...", "operator": "...", "value": ...}. Every field must be one this resource's /v1/filters/{resource}/ lists, and every operator must be one of that field's advertised operators.
  • logic — how multiple filters combine. One of:
    • "all" (default) — every filter must match (AND).
    • "any" — at least one filter must match (OR).
    • "custom" — arbitrary boolean grouping, paired with an expression string like "1 AND (2 OR 3)" referencing filters by their 1-based position in the filters list. expression is only used, and only required, when logic is "custom"; omitting it while logic="custom" is a 400.
  • columns — an optional comma-separated string of field keys to include in each result row. Omit it to get a default column set.

An invalid logic value is rejected before your filters are ever evaluated:

{
  "error": {
    "code": "invalid_argument",
    "message": "logic must be one of ['all', 'any', 'custom']."
  }
}

Companies: full field allowlist

Every key below is valid both as a search filters.field (if it has operators) and as a columns entry. unit is the unit to pass numeric threshold values in. As of v1; the live source of truth is GET /v1/filters/companies/.

Field keyTypeOperatorsUnitLabel
namestring— output onlyCompany
market_cap_in_usdnumbergte, lteUSDMarket Cap
total_cash_in_usdnumbergte, lteUSDCash in Bank
cash_runway_monthsnumbergte, ltemonthsCash Runway
hq_countrystring— output onlyHQ
websitestring— output onlyWebsite
exchangesselecthas_any, has_onlyExchanges (options: /exchanges/options/)
industryselecthas_anyIndustry (options: /industries/options/)
ownership_typeselecthas_anyOwnership (options: /ownership-types/options/)
commoditiesselecthas_any, has_onlyPrimary commodities (options: /commodities/options/)
by_productsselecthas_anyBy-products (options: /commodities/options/)
all_commoditiesselecthas_any, has_onlyAll commodities (options: /commodities/options/)
asset_phasesselecthas_any, has_onlyPhases (options: /mining-asset-phases/options/)
asset_stagesselecthas_any, has_onlyStages (options: /mining-asset-stages/options/)
asset_permitsselecthas_anyAsset permits (options: /mining-asset-permits/options/)
asset_milestonesselecthas_anyAsset milestones (options: /mining-asset-milestones/options/)
stock_pricenumber— output onlyStock Price
change_1dchange_5y, change_ytdnumbergte, lte%N-period stock price change (1D/1W/1M/3M/6M/1Y/2Y/3Y/4Y/5Y/YTD)
symbolstring— output onlySymbol
currency_symbolstring— output onlyCurrency
stock_price_currency_symbolstring— output onlyStock Price Currency
stock_price_tickerstring— output onlyStock Price Listing
asset_world_regionsselecthas_any, has_onlyWorld regions (options: /world-regions/options/)
asset_countriesselecthas_any, has_onlyCountries (options: /countries/options/)
asset_provincesselecthas_any, has_onlyProvinces / states (options: /provinces/options/)
price_sync_datedate— output onlyPrice Sync Date
companyselecthas_anyFilter-only: scope by specific company id (options: /companies/options/); never appears as an output value

change_1d, change_1w, change_1m, change_3m, change_6m, change_1y, change_2y, change_3y, change_4y, change_5y, and change_ytd are 11 separate keys, each independently filterable/requestable with the same gte/lte %-unit shape.

Mining assets: full field allowlist

As of v1; the live source of truth is GET /v1/filters/mining-assets/.

Field keyTypeOperatorsUnitLabel
namestring— output onlyMining Asset
primary_commodityselecthas_anyPrimary Commodity (options: /commodities/options/)
commoditiesselecthas_any, has_onlyAll Commodities (options: /commodities/options/)
by_productsselecthas_anyBy-products (options: /commodities/options/)
world_regionsselecthas_anyWorld Regions (options: /world-regions/options/)
countryselecthas_anyCountry (options: /countries/options/)
phaseselecthas_anyPhase (options: /mining-asset-phases/options/)
stageselecthas_anyStage (options: /mining-asset-stages/options/)
activity_statusselecthas_anyActivity Status (options: /mining-asset-activity-statuses/options/)
milestones_reachedselecthas_anyMilestones (options: /mining-asset-milestones/options/)
granted_permitsselecthas_anyPermits (options: /mining-asset-permits/options/)
asset_typeselecthas_anyAsset Type (options: /asset-types/options/)
mine_typeselecthas_anyMine Type (options: /mine-types/options/)
deposit_typeselecthas_anyDeposit Type (options: /deposit-types/options/)
provinceselecthas_anyProvince/State (options: /provinces/options/)
locationstring— output onlyLocation
primary_company_namestring— output onlyPrimary Company
primary_company_market_cap_in_usdnumbergte, lteUSDCompany Market Cap
exchangesselecthas_any, has_onlyCompany exchanges (options: /exchanges/options/)
primary_company_price_sync_datedate— output onlyPrice Sync Date
mining_methodstring— output onlyMining Method
processing_methodstring— output onlyProcessing Method
facility_typeselecthas_anyFacility Type (options: /facility-types/options/)
latest_economic_assessment_effective_datedategte, lteStudy Date
latest_economic_assessment_study_typestring— output onlyStudy Type
latest_economic_assessment_npv_usdnumbergte, lteUSDStudy NPV (post-tax, USD)
latest_economic_assessment_discount_ratenumber— output onlyNPV Discount
latest_economic_assessment_irrnumbergte, lte%Study IRR (post-tax)
latest_economic_assessment_capex_usdnumbergte, lteUSDStudy Initial CapEx
npv_to_capexnumber— output onlyNPV / CapEx
latest_economic_assessment_mine_life_yearsnumber— output onlyMine Life
latest_drill_results_datedategte, lteLatest Drill Results Date
drillhole_countnumbergte, lteDrillhole Count
best_interval_valuenumbergte, lte$·m/tBest Drill Interval Value
mining_assetselecthas_anyFilter-only: scope by specific mining asset id (options: /mining-assets/options/); never appears as an output value
companyselecthas_anyFilter-only: scope assets to a set of companies via their current owning relation (options: /companies/options/); never appears as an output value

POST /v1/publications/search/ and POST /v1/people/search/ have no curated vocabulary layer — there's no /v1/filters/ equivalent for them and no allowlist to reject against. What follows is transcribed from what each search actually accepts.

Publications

POST /v1/publications/search/:

ParamTypeDefaultNotes
querystring""Free text; empty string is a valid no-op query.
scopestring"both"One of body, title, both. An unrecognized value is a 400.
company_idsarray of intnullFilter by one or more company ids.
mining_asset_idintnullFilter by a single asset id.
content_kindstring or arraynullMust be a valid content-kind value (400 otherwise).
content_variantstring or arraynullMust be a valid content-variant value.
topicsarray of intnullTopic ids.
source_typestring or arraynullMust be a valid source-type value.
exchange_idsarray of intnullFilter by exchange id(s).
published_after / published_beforeISO date stringnullA non-ISO string is a 400.
orderstring"newest"One of newest, oldest, relevance. relevance with an empty query is a 400.
limitint20Clamped to 1–50 (non-numeric falls back to the default rather than erroring).
offsetint0Clamped to ≥ 0.

The response adds one key beyond the standard results/count/truncated shape: scope. This is not an echo of the request's scope string — it's {"entity_type": "company" | "mining_asset", "id": <id>} when the query resolves to exactly one company or one asset (via company_ids/ mining_asset_id), otherwise null.

People

POST /v1/people/search/:

ParamTypeDefaultNotes
querystring""Free text, whitespace-split; each term is AND-matched (case-insensitive contains) against name, aliases, and primary company.
limitint10Clamped to 1–25.
offsetint0Clamped to ≥ 0.

Response is the standard {results, count, truncated} shape — no extra keys. Unlike publications, no input here raises a 400 — every parameter is clamped or defaulted rather than validated. The only 400 you can get from this endpoint is DRF's own unparseable-JSON ParseError ({"detail": "..."}), not the {"error": {...}} envelope.

Both endpoints can return a 408 (query_timeout) if the query runs past the server's statement timeout — narrow your search term (or, for publications, add a company/date filter) and retry.

Resolving option values

GET /v1/options/{path}/

For select-type fields, use the field's options_endpoint (from /v1/filters/{resource}/, or the tables above) to look up the exact {id, label} pairs valid for that filter — rather than guessing at spellings or internal ids. To call it, strip the leading/trailing slashes from options_endpoint's value and drop it into the {options_path} segment of this route — an options_endpoint of /commodities/options/ becomes GET /v1/options/commodities/options/.

curl "https://api.pulseintelligence.com/v1/options/commodities/options/?query=gold&limit=5" \
  -H "Authorization: Bearer pulse_a1b2c3d4_<secret>"
{
  "query": "gold",
  "matches": [
    { "id": 1, "label": "Gold" }
  ]
}
  • query — the search term to resolve (empty string returns the top matches unfiltered).
  • limit — maximum number of matches to return (default 10).

The id type nuance

matches[].id is not always the same type — it's an integer for options backed by a real database model (companies, mining assets, commodities, exchanges, countries, provinces, world regions, topics, case categories), and a string for options backed by a static choice enum (statuses, types, phases, and similar closed vocabularies). Don't assume one shape — read the type back from the response and pass it through unchanged as the filter value.

Allowed options paths

{path} isn't arbitrary — only this bounded set of reference-data endpoints is resolvable (the same allowlist Pulse's MCP server enforces for resolve_options):

Options pathResolvesid type
asset-types/optionsMining asset typesstring
case-categories/optionsSupport case categoriesinteger
commodities/extraction-optionsExtraction-eligible commoditiesinteger
commodities/optionsCommoditiesinteger
companies/optionsCompaniesinteger
content-kinds/optionsPublication content kindsstring
content-variants/optionsPublication content variantsstring
countries/optionsCountriesinteger
deal-statuses/optionsDeal statusesstring
deal-types/optionsDeal typesstring
deposit-types/optionsMining asset deposit typesstring
exchanges/optionsStock exchangesinteger
facility-types/optionsMining asset facility typesstring
hole-types/optionsDrill hole typesstring
industries/optionsIndustriesstring
mine-types/optionsMine typesstring
mining-asset-activity-statuses/optionsMining asset activity statusesstring
mining-asset-milestones/optionsMining asset milestonesstring
mining-asset-permits/optionsMining asset permitsstring
mining-asset-phases/optionsMining asset phasesstring
mining-asset-stages/optionsMining asset stagesstring
mining-assets/optionsMining assetsinteger
ownership-basis/optionsOwnership basisstring
ownership-types/optionsCompany ownership typesstring
production-period-types/optionsProduction period typesstring
production-value-types/optionsProduction value typesstring
provinces/optionsProvinces / statesinteger
shareholder-statuses/optionsShareholder statusesstring
source-types/optionsPublication source typesstring
tenure-statuses/optionsTenure statusesstring
tenure-types/optionsTenure typesstring
topics/optionsPublication topicsinteger
world-regions/optionsWorld regionsinteger

Calling an endpoint outside this allowlist — or one that's excluded because it's per-user data rather than reference data (like a saved company set) — 400s:

{
  "error": {
    "code": "invalid_argument",
    "message": "Unknown options endpoint: bogus/options",
    "options_endpoint": "bogus/options"
  }
}

A non-integer limit also 400s the same way, rather than silently falling back to a default:

{
  "error": {
    "code": "invalid_argument",
    "message": "limit must be an integer, got 'abc'"
  }
}

Worked example: discover, search, resolve

One coherent flow: find what's filterable on companies, build a two-clause search, then resolve an option id for a select field.

1. Discover the vocabulary:

curl https://api.pulseintelligence.com/v1/filters/companies/ \
  -H "Authorization: Bearer pulse_a1b2c3d4_<secret>"

This response (see Companies: full field allowlist above) tells you market_cap_in_usd takes gte/lte with no option resolution needed, and commodities takes has_any/has_only with options_endpoint: "/commodities/options/".

2. Resolve the commodity you want to filter by:

curl "https://api.pulseintelligence.com/v1/options/commodities/options/?query=gold&limit=3" \
  -H "Authorization: Bearer pulse_a1b2c3d4_<secret>"
{
  "query": "gold",
  "matches": [
    { "id": 1, "label": "Gold (Au)" }
  ]
}

3. Build the two-clause search using the resolved id:

curl https://api.pulseintelligence.com/v1/companies/search/ \
  -H "Authorization: Bearer pulse_a1b2c3d4_<secret>" \
  -H "Content-Type: application/json" \
  -d '{
    "filters": [
      { "field": "market_cap_in_usd", "operator": "gte", "value": 100000000 },
      { "field": "commodities", "operator": "has_any", "value": [1] }
    ],
    "logic": "all",
    "columns": "name,symbol,market_cap_in_usd,commodities"
  }'

This returns gold companies with a market cap of at least $100M, with just the four requested columns in each result row.

Go deeper

  • Rate limits and errors covers the error envelope shape and quota headers referenced throughout this guide.
  • The API Reference has the full schema for /v1/filters/{resource}/ and /v1/options/{path}/, plus every search and dossier endpoint.

On this page