API reference
People
Search profiles with a Query Spec tree, or ask in plain language. Both return encrypted profile IDs, and the detail route turns those IDs into records.
- Routes
- 3
- Search
- /v1/people/query
- Search returns
- encrypted IDs
- Detail batch
- up to 100 IDs
- POST
/v1/people/queryQuery Spec search - POST
/v1/people-searchNatural-language search - POST
/entity/v1/profiles/detail-by-idFetch profile records
Search, then fetch
Search never returns profile records. It returns encrypted string IDs, and you pass up to 100 of them to the detail route to read the records. There is no one-shot endpoint, so plan for two calls.
# 1. Search. Returns encrypted IDs, never records.
curl -X POST "https://mira-api.metix.ai/v1/people/query" \
-H "Authorization: Bearer $METIX_KEY" \
-H "Content-Type: application/json" \
-d '{
"where": {"all": [
{"field": "city", "eq": "San Francisco"},
{"has_experience": {"all": [
{"field": "company_name", "match": "Google"},
{"field": "level", "eq": "Director"},
{"field": "is_current", "eq": true}
]}}
]},
"size": 25
}'
# 2. Read the records, up to 100 IDs per call.
curl -X POST "https://mira-api.metix.ai/entity/v1/profiles/detail-by-id" \
-H "Authorization: Bearer $METIX_KEY" \
-H "Content-Type: application/json" \
-d '{
"profile_ids": ["kR3nQv8xTm", "9tQmLd2wYb"],
"_source": ["profile_id", "full_name", "active_experience_title", "skills"]
}'Two calls, always
When to use it
- Build a profile set by role, skills, employer, education, location, or seniority.
- Express what a flat filter list cannot: alternatives, negation, and numeric or date ranges.
- Ask for a person who held one specific job, rather than a person who separately matched two facts.
- Ask in natural language when the constraints are awkward to write out as a tree.
Request parameters and limits
- Parameter
- where
- Type
- object
- Notes
- Query Spec tree. Required by /v1/people/query
- Parameter
- size
- Type
- integer (1-10000)
- Notes
- Profile IDs in one page. Omitting it returns 100
- Parameter
- after
- Type
- string
- Notes
- Cursor. Pass the next value from the previous response
- Parameter
- text
- Type
- string (1-5000 chars)
- Notes
- Natural-language question for /v1/people-search. That route accepts text and size only
- Parameter
- profile_ids
- Type
- string[] (1-100)
- Notes
- IDs from a search, sent to the detail route
- Parameter
- _source / source
- Type
- array, object, or boolean
- Notes
- Field selection on detail. Omit it for the default record; name fields to trade it for a narrower or a wider one
- One operator per leaf. A bounded range is an all of two leaves, not gte and lte in one node. This is the first mistake almost every caller makes.
- A field name that is not in this dataset's list is refused, so a typo is visible rather than returning a record without it. The three datasets do not share one vocabulary.
- Search returns at most 10,000 IDs per page and 100 when size is omitted; detail accepts at most 100 IDs per request.
- Scope nodes exist for people only. Jobs and companies are one document each, so there is nothing to group.
- Every Query Spec search reports total: an exact integer below 100000, and the string "100000+" at or above it. It counts what matched, not what was returned. Read it as a union, not as an integer.
- Profile data is a periodically refreshed snapshot and can lag real-world changes.
- The default record is a subset. Naming fields in _source reaches the full published set: the subject's own links and prose, their employer as a company, and their institution.
- Prose fields carry no email addresses or phone numbers. Contact data is a separate surface with its own pricing.
Credit cost
Queryable fields
These are the only names a leaf may put in field. The grammar around them, including composition, one operator per leaf, and relative dates, is on the Query Spec page. What a response may contain is a separate, wider list: a field can be returnable without being queryable.
active_titleactive_departmenttitleheadlineRole text. active_title and active_department describe the current job; title matches any job held.
active_titleactive_departmenttitleheadlineOperators: match, eq, in, exists
{
"where": {
"all": [
{
"field": "active_title",
"match": "machine learning engineer"
},
{
"field": "country",
"eq": "United States"
}
]
}
}company_nameinstitution_nameEmployer and school names.
company_nameinstitution_nameOperators: match, eq, in, exists
{
"where": {
"all": [
{
"has_experience": {
"all": [
{
"field": "company_name",
"match": "Google"
},
{
"field": "is_current",
"eq": true
}
]
}
}
]
}
}skillslanguagescertificationscoursesawardspublicationspatentsmajorList and free-text attributes attached to the person.
skillslanguagescertificationscoursesawardspublicationspatentsmajorOperators: match, eq, in, exists
{
"where": {
"all": [
{
"field": "skills",
"match": "kubernetes"
},
{
"has_language": {
"all": [
{
"field": "languages",
"eq": "Chinese"
}
]
}
}
]
}
}language_proficiencyHow well one language is spoken, as one of five levels. Put it in the same has_language as the language it describes, or it will be satisfied by any language on the profile.
language_proficiencyOperators: eq, in, exists
{
"where": {
"all": [
{
"has_language": {
"all": [
{
"field": "languages",
"eq": "Chinese"
},
{
"field": "language_proficiency",
"eq": "Professional working proficiency"
}
]
}
},
{
"field": "country",
"eq": "United States"
}
]
}
}full_namefirst_namelast_namelinkedin_urlIdentity, matched exactly.
full_namefirst_namelast_namelinkedin_urlOperators: eq, in, exists
{
"where": {
"all": [
{
"field": "full_name",
"eq": "Maria Garcia"
}
]
}
}citystatecountrycountry_iso2country_iso3regionsWhere the person is. country takes a name such as United States.
citystatecountrycountry_iso2country_iso3regionsOperators: eq, in, exists
{
"where": {
"all": [
{
"field": "city",
"eq": "San Francisco"
},
{
"field": "country",
"eq": "United States"
}
]
}
}workplace_cityworkplace_stateworkplace_countryWhere a job is. Most useful inside has_experience, where it binds to one job.
workplace_cityworkplace_stateworkplace_countryOperators: eq, in, exists
{
"where": {
"all": [
{
"has_experience": {
"all": [
{
"field": "workplace_city",
"eq": "Berlin"
},
{
"field": "is_current",
"eq": true
}
]
}
}
]
}
}rolelevelmanagement_levelindustrycompany_typePlatform vocabulary, matched exactly rather than fuzzily.
rolelevelmanagement_levelindustrycompany_typeOperators: eq, in, exists
{
"where": {
"all": [
{
"has_experience": {
"all": [
{
"field": "role",
"eq": "Engineering and Technical"
},
{
"field": "level",
"eq": "Director"
},
{
"field": "is_current",
"eq": true
}
]
}
}
]
}
}is_workingis_decision_makeris_currentis_studyingBooleans. is_current and is_studying describe a record, so they belong in a scope.
is_workingis_decision_makeris_currentis_studyingOperators: eq, in, exists
{
"where": {
"all": [
{
"field": "is_working",
"eq": true
},
{
"field": "is_decision_maker",
"eq": true
}
]
}
}experience_monthsduration_monthsTime spans in months. experience_months is career total; duration_months is one job.
experience_monthsduration_monthsOperators: gte, lte, exists
{
"where": {
"all": [
{
"field": "experience_months",
"gte": 60
},
{
"field": "experience_months",
"lte": 180
}
]
}
}company_employees_countcompany_size_rangeEmployer size. company_size_range is an ordinal band, so it compares as a number.
company_employees_countcompany_size_rangeOperators: gte, lte, exists
{
"where": {
"all": [
{
"has_experience": {
"all": [
{
"field": "company_employees_count",
"gte": 1000
},
{
"field": "is_current",
"eq": true
}
]
}
}
]
}
}degree_levelinstitution_rankinggraduation_yearstudy_start_yearEducation, as ordinals and years.
degree_levelinstitution_rankinggraduation_yearstudy_start_yearOperators: gte, lte, exists
{
"where": {
"all": [
{
"has_education": {
"all": [
{
"field": "degree_level",
"gte": 2
},
{
"field": "major",
"match": "computer science"
}
]
}
}
]
}
}started_atended_atJob dates. Takes YYYY-MM-DD or a relative offset such as now-6m.
started_atended_atOperators: gte, lte, exists
{
"where": {
"all": [
{
"has_experience": {
"all": [
{
"field": "ended_at",
"gte": "now-1y"
}
]
}
}
]
}
}Same-record scopes
Fields with a fixed set of values
These are matched against the whole stored value, so the spelling and the capitalisation both have to match. Getting either wrong is the one mistake in the grammar that raises no error: the query is valid, it costs nothing, and it returns zero, which reads as an answer about the data rather than about the query.
- Field
- language_proficiency
- Values
Elementary proficiencyLimited working proficiencyProfessional working proficiencyFull professional proficiencyNative or bilingual proficiencyThe whole scale, lowest to highest. A record carries the same five strings, so a level you read is a level you can filter on. Nothing else is accepted, including numbers and words like fluent or advanced, because those mean different levels to different people.
- Field
- management_level, level
- Values
SpecialistSeniorManagerHeadDirectorVice PresidentPresident/Vice PresidentC-LevelPartnerFounderOwnerInternlevel is the same set inside has_experience, where it describes one job rather than the person.
- Field
- active_department
- Values
AdministrativeC-SuiteConsultingCustomer ServiceDesignEducationEngineering and TechnicalFinance & AccountingGeneral ManagementHuman ResourcesLegalMarketingMedicalOperationsOtherProductProject ManagementReal EstateResearchSalesTrades
- Field
- industry
- Values
Accommodation ServicesAdministrative and Support ServicesConstructionConsumer ServicesEducationEntertainment ProvidersFarming, Ranching, ForestryFinancial ServicesGovernment AdministrationHolding CompaniesHospitals and Health CareManufacturingOil, Gas, and MiningProfessional ServicesReal Estate and Equipment Rental ServicesRetailTechnology, Information and MediaTransportation, Logistics, Supply Chain and StorageUtilitiesWholesaleThis is the twenty-value set used on a person's experience. A company's own industry field is a different, much longer vocabulary.
Not every category field is a fixed set
Response shape
Successful responses use the public envelope with code, msg, and data.
Search returns IDs, and a next cursor while more pages remain:
{
"code": 200,
"msg": "ok",
"data": {
"profile_ids": ["kR3nQv8xTm", "9tQmLd2wYb"],
"total": 418,
"next": "WzE3MjQwMDAwMDAsImtSM25Rdjh4VG0iXQ"
}
}Detail returns the records, and names the IDs it could not resolve:
{
"code": 200,
"msg": "ok",
"data": {
"total": 2,
"found": 1,
"not_found": ["9tQmLd2wYb"],
"results": [{
"profile_id": "kR3nQv8xTm",
"full_name": "Example Profile",
"active_experience_title": "Staff Machine Learning Engineer",
"skills": ["Python", "distributed training"]
}]
}
}The record itself is a page of its own: every field it can carry, what each one holds, and a whole one to read.
Access surfaces
- Surface
- REST
- How to use this capability
- POST /v1/people/query; POST /v1/people-search; POST /entity/v1/profiles/detail-by-id
- Surface
- Metix AI skill
- How to use this capability
- metix-people-search
- Surface
- MCP
- How to use this capability
- Use the MCP setup page to expose the same REST capability. Capability-specific tool names remain pending schema verification.
- Surface
- Natural-language prompt
- How to use this capability
- Find people who are currently directors at Google and based in San Francisco, then fetch their full records and summarize their skills.
Common next step: search the jobs dataset.