From a Project Brief to a Search

Briefs arrive as prose. This guide turns one into a request body, end to end. Someone writes down who they want to talk to: a vendor whose customers matter, a seniority band, a list of job titles, a page of priority accounts. Someone else has to make that a filter set.

The brief below is synthetic, and so is its phrasing; real briefs word these headings a dozen different ways. What is consistent is the set of things they specify, and that is what the translation hangs on.

Enterprise data platform selection

We want to understand how large organizations pick, migrate between, and consolidate data platforms. Ideal conversations are with people who have personally run or sat on one of those evaluations.

Platform in focus — Snowflake Data Cloud

Nearby products count too — anything in the Data Warehousing category

Where they work — enterprise data infrastructure: warehousing, analytics engineering, BI tooling, and the platform teams that own them

How senior — Director, VP, SVP, or C-level

Which teams — data engineering, analytics, platform and infrastructure engineering, enterprise applications, procurement and vendor management

Titles we tend to see (a flavour, not a checklist) — VP of Data, Director of Data Engineering, Head of Analytics, Chief Data Officer, Director of Data Platform, Enterprise Data Architect, Procurement Lead

Accounts to start with — Salesforce, Henry Schein, Patterson Companies, then widen from there

How recent — still in the role, or left it within the past 12 months

Where — United States

Synthetic example — invented client, accounts, and vendor of interest

Read the brief as four questions#

Every line above answers one of four questions, and each maps to a different part of the request. Sorting the prose into these buckets first is most of the work:

QuestionIn the briefBecomes
Anchor — what makes a company relevant?The platform in focus, and the category around itvendorgraphics.aggkProductId
Persona — who at that company?How senior, which teams, and the titles they expect to seeworkExperience.seniority / role / subrole / jobTitle
Scope — which of those count?Geography, how recent the role must be, the sector they sit inperson.country, employmentStatus, endDate, company.industry
Priority — who do they want first?A short account list, plus an instruction to widen past itA separate tier — not a filter. See step 4.

Step 1 — resolve the names to IDs#

The brief names a product and a list of companies. The product must become an ID before you can filter on it; the companies do not have to, but usually should. This is the step most integrations skip, and it is where a brief quietly goes wrong — “Snowflake” the company is not Snowflake Data Cloud the product, and a brief naming a vendor’s product family (“Marketing Cloud” vs “Commerce Cloud”) needs the right one of several catalog entries.

Product name → aggkProductId
curl --request POST \
  --url https://api.aggknowledgeai.com/v2/live/vendorgraphics/search/products \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: YOUR_API_KEY' \
  --data '{ "productName": "Snowflake Data Cloud" }'

That returns product 48211, in category 1785 (Data Warehousing) — which is also the answer to the brief’s nearby-products line, since a category filter covers every product in it.

Run the priority company names through Company Match the same way, one call per name, and keep the id of each confident hit. Ambiguous names should be reviewed rather than guessed — see Company Matching. For this brief that yields 44002816, 65731533, and 44510632.

Names or IDs?#

Companies can also be filtered by name directly, with no resolve step — company.companyName is a phrase match against the company’s name, so { "or": ["salesforce"] } matches any company whose name contains that phrase. That is the fast path, and it is genuinely the right choice for exploring a brief before committing to it. For the search you actually deliver, resolving to IDs is usually worth the extra calls:

 companyNameaggkCompanyId
SetupNoneOne Company Match per name, plus review of ambiguous hits
PrecisionPhrase collisions — “delta” also matches Delta Dental and Delta FaucetExactly the companies you picked
Alternate spellings“J.P. Morgan” and “JPMorgan” do not match each otherWhat Match’s scoring exists to resolve
SubsidiariesIncluded by accident — “wells fargo” also catches Wells Fargo AdvisorsIncluded on purpose, via company.expansion (v3)
AuditabilityYou cannot see which companies the phrase resolved toAn explicit list you can review and hand back with the results
StabilityThe population shifts as new companies with colliding names appearFixed until you re-resolve

The deciding factor is usually not precision but reuse: a resolved ID list is an artifact you can store against the brief, re-run next quarter, and show someone. A name filter is re-interpreted on every request.

Tip: Store the resolved IDs against the brief. Briefs get revised — a second round with five more accounts should not mean re-resolving the first fifty.

Step 2 — translate the persona#

Three separate brief lines describe one person, and they do different jobs in the request.

Seniority is a band, and it does not map one-to-one#

“Director, VP, SVP, or C-level” is four stated bands but three vocabulary values — there is no svp. Senior vice presidents normalize to vp:

Seniority
"seniority": { "or": ["director", "vp", "cxo"] }

Teams become roles and subroles#

The brief’s team list is prose covering several distinct groups. Map each to the closest role, and reach for subrole where the brief is more specific than a role can express — “data engineering” and “procurement” are subroles, not roles:

Function
"role": { "or": ["engineering", "analyst", "operations"] },
"subrole": {
  "or": ["data_engineering", "data_science", "data_analyst",
         "information_technology", "procurement"]
}
Warning: role and subrole are single-valued per work experience — one person’s job has one of each. Use or to mean “any of these”. Passing two values as and can never match, and returns zero results rather than an error.

Title keywords refine — they do not replace#

Briefs hedge their title lists — a flavour, not a checklist — for a reason: the author is describing a shape, not enumerating the population. jobTitle is the one analyzed-text filter in Discover, matched against both the stored title and its English translation, so it is the right tool for those keywords — but it should sit on top of role and seniority, not replace them. A search filtered only by title finds the titles someone happened to think of.

OperatorMeansUse it for
jobTitle.ortitle matches any one of these entriesA list of alternative titles from the brief
jobTitle.andevery term appears in one titleNarrowing a concept — “data” + “architect”

Terms within a single value are already ANDed, so “data platform” requires both words in the same title. jobTitle is the only field where multi-value and behaves this way; everywhere else it is a trap.

Step 3 — scope it#

A bare country name is ambiguous in a way worth resolving with whoever wrote the brief. person.country is where the person is; company.country is where their employer is headquartered. For interview recruiting you almost always want the person.

“Still in the role, or left it within the past 12 months” is a union, not one filter: people currently in the role, plus people who left within the year. The two arms disagree on employment status, so they cannot share a filter block — which is what step 4 is about.

Step 4 — priority accounts are a tier, not a filter#

This is the part briefs get mistranslated most often. A named account list followed by then widen from there is a ranking instruction, not a restriction: start with these companies, then keep going. Filtering the search down to the list throws away everything past it — and dropping the list loses the priority.

v2 Advanced takes one filter block, so a tiered brief is several searches you merge yourself: one restricted to the priority company IDs, one for the broader product-customer population, and — because the brief also wants recent leavers — an employment-status variant of each. Deduplicate on the person id, keeping the highest-priority tier each person appeared in.

Switch this page to v3 to see the same brief as a single request with named groups.

Tier 1 — priority accounts, current employees
{
  "company": {
    "aggkCompanyId": { "or": [44002816, 65731533, 44510632] }
  },
  "workExperience": {
    "seniority": { "or": ["director", "vp", "cxo"] },
    "subrole": {
      "or": ["data_engineering", "data_science", "data_analyst",
             "information_technology", "procurement"]
    },
    "personFilter": "CURRENT"
  },
  "person": {
    "personCountry": { "or": ["united states"] }
  }
}
Tier 2 — the broader market, current employees
{
  "vendorgraphics": {
    "aggkProductId": { "or": [48211] },
    "filterByDetectionPeriod": true,
    "detectionPeriodBuffer": "SIX_MONTHS"
  },
  "workExperience": {
    "seniority": { "or": ["director", "vp", "cxo"] },
    "subrole": {
      "or": ["data_engineering", "data_science", "data_analyst",
             "information_technology", "procurement"]
    },
    "personFilter": "CURRENT"
  },
  "person": {
    "personCountry": { "or": ["united states"] }
  }
}

Repeat both with “personFilter”: “PAST_NOT_CURRENT” and “endDate”: { "gte": "2025-08" } to pick up the recent leavers.

Listing company IDs alongside a product widens the search — it does not narrow it. Within one filter group, company.aggkCompanyId.or is unioned with the companies the product filter resolves to, so a listed account appears whether or not it uses the product. That is deliberate: naming a company by ID is read as stated intent.

companyName behaves the opposite way — it is an ordinary filter, so it intersects with the product’s companies rather than widening past them. So if what you want is “these accounts, and only where they use the product”, there are two routes:

  • Name filter, one request — put the account names in company.companyName.or alongside the vendorgraphics filter, and the group returns only the overlap. Cheap, but inherits every imprecision in the names-or-IDs tradeoff above.
  • Intersect the IDs yourself — run Product customer search for the product, keep the IDs it shares with your matched priority list, and pass only those as aggkCompanyId with no product filter. More calls, exact result, and you can see the overlap before searching.
Tip: grouping.maxResultsPerCompany keeps one large employer from consuming the whole page — worth setting on any brief whose priority list mixes very large and very small organizations.

Step 5 — size each tier before you crawl it#

Check tiers individually rather than in aggregate: a brief is usually over-broad in exactly one place, and a single total hides which.

Run Count results with each tier’s body. It is free on both versions and answers past the paging ceiling, so it also settles the question briefs love to ask in passing — “roughly how many are there, with no cap?”

One caveat when you quote that number back: the v2 count is over work experiences, so a person holding two matching roles is counted twice and the figure reads high against the people you will actually page through.

Run Validate request on the document once too. It is also free, and it catches the mistakes a tiered brief invites: an invalid seniority or industry value, a filter placed under the wrong entity, and — on v3 — filters left at the root instead of inside an or group. Warnings name the filter group they came from, which matters once you have four.

A search still returns at most 5,000 people on either version. If a tier is bigger than that, slice it — by region, by employee-count band, or by sub-function — and page each slice. See How Discover Works.

What the brief is asking for that Discover cannot express#

Some lines in a brief are screening criteria, not filters. Discover produces the population; qualification happens afterwards, in a screener or a conversation. Reading these as filters is how a search ends up empty:

The brief asks forDiscover canYou still need to
Hands-on, frequent use of the productFind people at companies where the product was detected, and how recentlyScreen for individual usage — there is no seat- or session-level signal
Someone who sat on the evaluationFilter to the functions and seniorities that usually own itConfirm involvement; role is a proxy for it, not evidence of it
Views on a particular themeNothing — a theme is not an attributeTreat it as the screener’s subject, not a filter
An account list to start from, then wider coverageTier the search so named accounts are identifiableDecide how deep into the broader tier to go
Vendorgraphic signals are inferred from many sources and describe an organization, not an individual. Treat a detection as a strong indication the company is a customer — not as proof that the person you found touches the product.

The finished loop#

  1. Resolve product and company names to IDs, and store them against the brief.
  2. Translate seniority, function, and titles — in that order of load-bearing weight.
  3. Apply scope: person geography, employment recency, industry.
  4. Express priority accounts as their own tier, not as a filter.
  5. Size each tier, slice anything over 5,000, then page.
  6. Enrich only the people who survive screening — Discover returns summaries, and the person’s id is what Person Enrich takes as personId.