/v1/search/jobsSubmit a deep (async) search job with a fill-to-target guarantee
search:deepdeep_searchesThe async agentic lane: round 0 runs the search-select agent (sweep, geo gate, enrichment, recruiter judgment) and the job stays running until you poll it; later rounds page deterministically, banking overflow and enforcing delivered-once uniqueness across the saved search. Requires the search:deep entitlement and consumes one DeepSearches quota unit. Billed one credit per candidate CONSIDERED, not per developer delivered: considered means the candidates the agent enriched and put in front of the recruiter judge, and the poll reports both numbers (progress.considered and progress.delivered) so you can read the ratio you paid for. Nothing is charged at submit; the poll settles it. A round that fails, or that considers nobody, costs nothing. When the agent host is unreachable the round degrades to the deterministic pager and bills that lane instead: one credit per developer delivered. exact vs best_effort is echoed on the job; an under-delivery is a clean partial either way. Set budgetCredits to cap what the whole job (every round) may cost: a budget below the round-0 estimate is refused here with a 402 before anything runs, and the job echoes budgetRemaining on every read.
Request body CreateSearchJobRequest
configobject requiredThe search config to run. Compile one from a job description with `POST /v1/searches/compile` if you do not have one.
versionnumber requiredMarks this as a version 2 config. The only required field alongside `query`.
2querystring | null requiredFree-text description of who you are looking for, matched semantically. This is the one field that carries the intent; every lever below narrows it.
max 500 charsentitystring default: "auto"Which index to search. Leave `auto` to let the compiler route. Pin one when a lever you need landed in `unsupported`: `User` searches GitHub developers, `Repo` searches repositories and returns their contributors, and `LinkedInUser` searches the LinkedIn overlay, which covers only the minority of developers we hold a match for and therefore reaches a much smaller population.
autoUserRepoLinkedInUserrequiredLanguagesarray of string default: []Programming languages that MUST be present, as a hard filter on repositories. This is the only language axis that hard-filters: `levers.skills` and `levers.technologies` are semantic aims. Set it only for languages you genuinely require, since it removes everyone else.
max 20 itemsearlyCareerSignalsboolean default: falseBias the search toward people early in their career: adds a learning-in-public angle and inverts the devrank weighting, so established high-reputation accounts stop dominating the ranking.
aiFocusedSignalsboolean default: falseBias every angle toward AI, agent, LLM, retrieval and inference work.
includeUnconventionalTitlesboolean default: falseKeep people whose job title is not a conventional engineering one but who ship code anyway. Leave false and the LinkedIn lane restricts to engineering functions.
leversobject default: {}The narrowing levers. Every one is optional and every collection defaults to empty, so a query-only config is a legal search and you set only the axes you actually want to constrain. Check `appliedLevers` and `unsupported` on the response to see which of them actually bound.
skillsarray of string default: []Demonstrated abilities, matched against what the person has actually built. A semantic aim, not a hard filter — use `requiredLanguages` when something is genuinely mandatory.
max 20 itemsinterestsarray of string default: []Topics and problem areas the person works on or gravitates toward. Distinct from `skills`, which is about demonstrated ability; the two are never collapsed. Setting this routes the search toward the repository lane.
max 20 itemstechnologiesarray of stringLanguages, frameworks and systems, drawn from a CLOSED vocabulary — a value outside it is rejected rather than silently treated as free text. This is the concrete tooling axis; `skills` stays the conceptual one.
max 20 itemslocationobjectWhere the person is. Every location signal here is SELF-REPORTED by the developer and never verified.
countriesarray of string default: []Countries, matched against our geocoding of the self-reported location.
max 20 itemscitiesarray of string default: []Cities, matched against our geocoding of the self-reported location.
max 20 itemsstatesarray of string default: []States or regions, matched against our geocoding.
max 20 itemsrawarray of string default: []Raw location strings, matched against what the developer literally typed on GitHub.
max 20 itemsstrictbooleanTrue to hard-gate on location, trading recall for precision. False or unset applies it as a bias. Remember that location is self-reported and frequently stale or blank, so a hard gate drops everyone who left the field empty.
requireLinkedinbooleanReturn only developers we hold a LinkedIn match for. A severe narrowing: only a minority of the indexed GitHub population carries an overlay, so this trades most of the corpus for professional detail.
openToWorkbooleanRestrict to people flagged as open to work on their LinkedIn profile. Requires the LinkedIn overlay, so it implies the same narrowing as `requireLinkedin`.
experienceTierstringA coarse experience band to aim at.
earlyupToSeniorseniorallyoeRangeobjectA years-of-experience band, derived from the LinkedIn overlay, so it only constrains people we hold one for.
mininteger | null requiredMinimum years of experience. Null for no lower bound.
min 0maxinteger | null requiredMaximum years of experience. Null for no upper bound.
min 0
professionalobjectEmployment and education levers. Every one of these comes from the LinkedIn overlay, so setting any of them implicitly restricts the search to the minority of developers we hold a match for.
currentCompaniesarray of string default: []Companies the person works at NOW.
max 20 itemspastCompaniesarray of string default: []Companies the person used to work at.
max 20 itemsmustHaveWorkedAtarray of string default: []Companies the person must have worked at at some point, current or past. The either-or form of the two fields above.
max 20 itemsexcludeCurrentCompaniesarray of string default: []Companies to exclude people currently working at. This is how you avoid sourcing out of your own company or a client’s.
max 20 itemsschoolsarray of string default: []Institutions the person attended.
max 20 itemstitlesarray of string default: []Job titles to aim at.
max 20 itemsindustriesarray of string default: []Industries the person works in.
max 20 itemscompanySizeTierstringThe size band of the person’s current employer.
1-5051-200201-20002000+companiesModestringHow the company lists bind. `exact` matches the named companies only. `similar` expands them to comparable companies, which widens reach at the cost of precision.
exactsimilarsimilarCompaniesarray of string default: []Companies to treat as reference points for "companies like these", rather than as an allowlist in themselves.
max 20 itemsincludePastbooleanMatch against the full employment history rather than the current employer only. Defaults to true.
githubobjectGitHub-side levers: stars, followers, seed repositories, and the devrank floor.
starRangeobject | null default: nullA star band on the person’s repositories. Null, the default, means no bound at all rather than a missing value.
mininteger | null requiredLower bound, inclusive. Null for no lower bound.
min 0maxinteger | null requiredUpper bound, inclusive. Null for no upper bound.
min 0
similarReposarray of string default: []Seed repositories, as `owner/name`. How they bind depends on `repoMode`: expanded to similar repositories, or matched exactly.
max 20 itemscontributedReposarray of string default: []Repositories the person COMMITS to rather than owns, as `owner/name`. This is how you find the people behind a repository they do not own — a company repo, or a large open-source project.
max 20 itemsminDevrankinteger | null default: nullA floor on devrank, the same 0–100 standing returned as `developer.stats.crackedScore`. Measured against the WHOLE indexed GitHub population rather than a peer group, so it is a blunt reputation gate and not a like-for-like comparison within a role. Null, the default, means no floor.
min 0, max 100hideHighProfilebooleanSuppress very high-profile accounts, which otherwise dominate a ranking without being realistic hires.
repoModestring default: "similar"How `similarRepos` binds. `similar`, the default, expands each seed to comparable repositories. `exact` matches only the repositories you named.
similarexactfollowerRangeobject | nullA band on GitHub follower count. Null bounds mean no limit on that side.
mininteger | null requiredLower bound, inclusive. Null for no lower bound.
min 0maxinteger | null requiredUpper bound, inclusive. Null for no upper bound.
min 0
minContributionsLastYearinteger | nullTHE DEAD-ACCOUNT GATE. A floor on GitHub contributions in the trailing 365 days; ANDs with minContributionsLastMonth when both are set. Recruiter Bot ships 100 here, and the absence of this floor is the single largest source of low-signal developers in a result set. This is NOT an index filter — the serving user index carries no activity column — so it is enforced after hydrate against a LIVE contribution-calendar read of the returned window only. Two consequences worth planning for: it narrows the page rather than the corpus (a tight floor can shorten a page, and countStatus reports it), and it is the one lever that costs a GitHub call, so an unset floor costs nothing at all. A developer GitHub did not answer for is KEPT, never dropped — the gate degrades open rather than emptying a page when the upstream is slow.
min 0, max 100000minContributionsLastMonthinteger | nullThe trailing-28-day half of the dead-account gate, ANDed with minContributionsLastYear when both are set and answered by the same single live read. Recruiter Bot ships 20 here. Catches the developer who was active earlier in the year and has since gone quiet, which the yearly floor alone lets through.
min 0, max 100000
filterobjectA raw filter expression, as an escape hatch for constraints the levers do not express. Opaque here and validated by the compiler; prefer the levers.
boostarray of object default: []Signal weights that RE-RANK results. These never filter anyone out: the signals available here have too little coverage to be used as a hard gate, so they only reorder what already matched.
max 20 itemssignalstring requiredThe signal to weight. Read `GET /v1/search/capabilities` for the signals that exist and whether each can be pushed to the index.
max 200 charsweightnumber requiredIts weight. Positive favours the signal, negative penalises it.
rankobjectHow to rank the results. Ranking today is page-local (see `rankScope` on the response), so this reorders the page rather than reaching deeper into the index.
presetstringA named ranking preset.
max 200 charsweightsarray of objectExplicit per-signal weights, as an alternative to a preset.
max 20 itemssignalstring requiredThe signal to weight.
max 200 charsweightnumber requiredIts weight.
targetobject requiredHow many developers this job should deliver, and how strictly.
countinteger requiredHow many developers you want. A count above the maximum is refused rather than silently clamped, so a job can never report a partial that was really us ignoring your number.
min 1, max 25modestring required`exact` to hold out for the full count, `best_effort` to take what the lane finds. Either way, an under-delivery is a clean partial.
exactbest_effort
savedSearchIdstring | nullAttach this job to a saved search. Doing so enforces delivered-once uniqueness across that saved search, so successive jobs never re-show the same developers.
max 16 charsprojectIdstring | nullAttach this job to a project, for grouping.
max 16 charsbudgetCreditsinteger | nullA hard ceiling on what this job may cost you IN TOTAL, across round 0 and every later `/more` round. Submit is refused with a 402 when the ceiling cannot cover the round-0 estimate (`creditsEstimated`) — the agentic round cannot be made smaller, so a budget it would blow means the job never runs and nothing is charged. A `/more` round is divisible, so it is truncated to what the remaining budget buys and refused with a 402 once nothing is left. The settled charge is clamped to the ceiling, so you are never billed above it. Poll `budgetRemaining` to see what is left; a refund puts credits back into it. Omit for no ceiling.
min 0, max 100000
Responses
200The durable job plus the developers delivered in round 0entitystringWhich index this query was actually routed to, after auto-routing. `User` = the GitHub developer index. `Repo` = repositories were searched and their contributors returned. `LinkedInUser` = the LinkedIn overlay, which covers only the minority of developers we hold a match for, so a query routed here reaches a much smaller population. The routing decides which levers can bind at all: pin `config.entity` and re-run if a lever you need landed in `unsupported`.
UserRepoLinkedInUserunsupportedarray of objectEvery lever you set that this lane could NOT apply as a hard filter. These are declared, never silently dropped — if a lever is listed here, the results were not filtered by it, so check this array before trusting a result set to satisfy a constraint. Each entry names a `route` that does serve the lever.
max 50 itemsleverstring requiredThe lever key that could not be applied, in the same dotted form you set it (`levers.github.contributedRepos`).
max 5000 charstierone ofHow this lever can be served at best. `1` = it is a real push-down filter on some lane. `2` = it can only re-rank or annotate, never hard-filter. `3` = it is only available on the asynchronous deep lane.
reasonstringPlain-language explanation of why this lever did not bind on this run.
max 5000 charsroutestringThe API path that DOES serve this lever, so the hint is directly actionable: `/v1/search/jobs` for the asynchronous deep lane, or `/v1/searches/execute` when another entity binds it (pin `config.entity` and re-run).
max 200 chars
appliedLeversarray of stringThe levers that DID bind on this page, by lever key. This is the other half of `unsupported`: every lever you set appears in exactly one of the two arrays, so you can tell a page that honoured all your constraints from one that honoured none — both otherwise look like a plausible list of developers.
max 50 itemsrankScopestringWhat population the ordering was computed over. `page` means only the returned rows were ranked against each other, so `score` is a within-page ordering and paging further can surface a better candidate than anything on page one. `index` would mean ranking ran index-wide. Today this is always `page`.
indexpagecountStatusone ofWhether you got the number of results you asked for, and if not, why. Never padded and never silently short.
jobSearchJob requiredThe durable job state after this round, including the credit counters.
idstring requiredThe job id. Poll `GET /v1/search/jobs/{id}` with it.
statusstring requiredWhere the job stands. A job is still working until it reaches a terminal status; poll rather than assuming a submit returned everything.
queuedrunningsucceededpartialfailedcanceledtargetCountinteger requiredHow many developers you asked this job to find.
targetModestring required`exact` = deliver the target count or report a clean partial. `best_effort` = deliver what the lane can find. Either way an under-delivery is reported as a partial, never padded.
exactbest_effortsavedSearchIdstring | null requiredThe saved search this job belongs to, when it was run from one. Delivered-once uniqueness is enforced across the saved search, so a later job will not repeat developers an earlier one delivered.
projectIdstring | null requiredThe project this job was run for, when one was named.
progressSearchJobProgress requiredCounts so far. Null before the first round has produced anything.
deliveredinteger requiredHow many developers this job has actually handed you so far, across all rounds. This is what you received, NOT what you paid for.
min 0bankedinteger requiredDevelopers found and held back beyond the current target, ready to be handed over by a `/more` round without re-running the search.
min 0roundinteger requiredHow many rounds this job has run. Round 0 is the agentic sweep; later rounds page deterministically.
min 0consideredinteger requiredHow many candidates this job was BILLED on: the ones the agent enriched and put in front of the recruiter judge, most of which are rejected before you ever see them. This is normally several times `delivered`, and the ratio between the two is what you paid for. On a round that fell back to the deterministic pager, billing is per developer delivered and this equals `delivered`.
min 0
errorstring | null requiredWhy a failed job failed, in plain words. Null on every job that ended well.
creditsEstimatedinteger requiredThe estimate made when the job was submitted. Nothing is charged at submit.
creditsChargedinteger requiredCredits actually charged so far. Settled as rounds complete, on candidates considered rather than delivered.
budgetCreditsinteger | null requiredThe ceiling you set on what this job may cost, in total, across every round. Null when you set none.
budgetRemaininginteger | null required`budgetCredits` minus `creditsCharged`: what is still spendable on this job. A `/more` round is truncated to what this buys, and refused with a 402 once it reaches 0. Refunds put credits back here, because it is derived rather than stored. Null when no ceiling was set.
createdAtstring requiredWhen the job was submitted, as an ISO 8601 instant.
updatedAtstring requiredWhen the job last changed, as an ISO 8601 instant.
deliveredarray of object requiredThe developers handed over by this round. Can be empty while the job is still running: submit returns as soon as round 0 is dispatched, so poll the job for the rest.
max 100 itemsdeveloperobject requiredThe developer’s profile.
developerIdstring requiredThe stable Vamo identifier for this developer (GitHub's numeric user id, stringified). This is the id every other endpoint takes: facets, reports, contacts, shortlists, steering. Use it, not `login` — a login can be renamed and then belongs to someone else.
max 64 charsloginstring requiredThe GitHub handle as of the last snapshot. Display it, do not key on it: handles are renameable and reusable.
max 200 charsnamestring | null requiredDisplay name as the developer set it on GitHub. Null when they set none.
max 200 charsavatarUrlstring | null requiredGitHub avatar image URL. Null when absent.
max 2048 charscurrentRolestring | null requiredA single free-text role line for the developer. Best-effort and unverified; `professional.title` is the LinkedIn-sourced equivalent when we hold a LinkedIn overlay.
max 200 charsorganizationobject | null requiredThe developer's current employer, when one is known. Null means we hold no employer, NOT that they are unemployed.
namestring requiredThe organization name as recorded.
max 200 charslogoUrlstring | null requiredOrganization logo URL, null when absent.
max 2048 chars
universitystring | null requiredMost recent institution, when the LinkedIn overlay carries education. Null when unknown.
max 200 charsprofilesobject requiredWhere this developer can be found, plus the addresses if you have already bought them.
githubstring requiredThe developer’s github.com profile URL. Always present — GitHub is the identity anchor for every developer in the index.
max 2048 charslinkedinstring | null requiredLinkedIn profile URL when we hold a GitHub↔LinkedIn match for this person. Null for the large majority of developers: only a minority of the indexed GitHub population carries a LinkedIn overlay, so null means "no match held", never "no LinkedIn account".
max 2048 charsemailsarray of stringEvery email address we hold for this developer. Present ONLY when this account has already paid to reveal them and the purchase is still within its cache window; a base search or profile read never populates it. ABSENT is not the same as "no email": absent means you have not bought it, while `hasEmail: false` means we hold none. These are addresses we have OBSERVED — from public commit metadata and cached GitHub profile data — and we do not check deliverability, so treat the order as meaningless and expect some to bounce. Buy them with the `contact.emails` facet.
max 50 items
hasEmailboolean requiredWhether we hold at least one email address for this developer. It says we have an address on file, not that the address works — we do not check deliverability. The addresses themselves are never returned by a search or a base profile read: this boolean is the free signal, and the paid `contact.emails` facet is the only way to get them. Use `hasEmail` on a search request to filter to developers we hold an address for, without paying.
biostring | null requiredThe developer’s GitHub bio, verbatim. Null when empty.
max 5000 charslocationobject | null requiredSelf-reported location, plus our geocoding of it. Self-reported and never verified against anything: a developer can leave it stale or blank. Null when we hold nothing at all.
rawstring | null requiredThe location string exactly as the developer typed it on GitHub ("SF / remote").
max 200 charscitystring | null requiredCity resolved from `raw` by geocoding. Null when `raw` was empty or unresolvable.
max 200 charscountrystring | null requiredCountry resolved from `raw`. Null when `raw` was empty or unresolvable.
max 200 chars
joinedAtstring | null requiredWhen the GitHub account was created, as an ISO 8601 instant. Null when unknown.
max 40 charsstatsobject | null requiredSnapshot counts and standing for this developer. These are from our index and go stale between refreshes; `GET /v1/developers/{id}` returns live GitHub equivalents alongside the contribution garden when you need current numbers. Null when we hold no stats at all.
followersinteger | null requiredGitHub follower count at snapshot time.
min 0, max 100000000followinginteger | null requiredHow many accounts this developer follows, at snapshot time.
min 0, max 100000000totalStarsinteger | null requiredSum of stargazers across the repositories ATTRIBUTED to this developer — the same set as `repos`, so the count can never contradict the list. Owned and contributed-to repositories both count; forks do not.
min 0, max 100000000crackedScorenumber | null requiredDevrank: a 0–100 standing for this developer within the WHOLE indexed GitHub developer population (tens of millions of accounts), not within a language, region, or seniority peer group — so it is not a like-for-like comparison between two candidates for the same role. It is derived from the follower/contribution graph, is recomputed upstream on its own schedule, and carries no version on the wire, so the same developer can read differently across two snapshots. It contributes one term to the page-local `score` and backs the `levers.github.minDevrank` filter. Null when the developer is not in the devrank table.
tierstring | null requiredThe upstream provider’s own coarse label for `crackedScore` (for example "Elite"). The label set is the provider’s and is not a Vamo-stable vocabulary — treat it as display text and branch on `crackedScore` if you need a threshold. Null when the developer is not in the devrank table.
max 200 chars
reposarray of object requiredThe developer’s top ATTRIBUTED public repositories — owned or authored-into, forks excluded — stars descending, capped at 12. This is a sample of their best work, not a complete repository list, and it is not an answer to "why did this person match my query" — read `evidence.matchedRepos` for that.
max 12 itemsnamestring requiredThe repository name alone, without the owner (`linux`).
max 200 charsfullNamestring requiredGitHub `owner/name`. This is the join key: an evidence repo and a profile repo describing the same repository carry the same `fullName`.
max 200 charsdescriptionstring | null requiredThe repository's own GitHub description, verbatim. Null when it has none.
max 5000 charslanguagestring | null requiredGitHub's primary language for the repository. Null when GitHub reports none (an empty or docs-only repo); never inferred from the code.
max 200 charsstarsinteger requiredStargazer count at the time this profile was snapshotted, not at request time.
min 0, max 100000000commitsintegerHow many commits THIS developer authored to this repository over the trailing year. This is the difference between a project they wrote and a project they landed one drive-by fix in — a 385k-star repository with 4 of their commits is not their work. Absent when no commit signal was captured; 0 means none in the trailing year, which for older dormant work is not the same as none ever.
min 0, max 100000000ownedbooleanTrue when the repository sits under the developer's own account, false when it is someone else's (an organisation's or another person's) and they are a contributor to it. This is the difference between "they built this" and "they committed to this", and it is the ONLY honest basis for crediting a repository's stars to a person. Absent when no ownership signal was captured; treat absent as unknown, never as false.
urlstring requiredThe public github.com URL of the repository.
max 2048 chars
languagesarray of string requiredDistinct primary languages across the developer’s repositories, at most 8. Presence means they have shipped public code in it; the list is not ranked by proficiency and carries no line counts.
max 8 itemsexperiencearray of object requiredEmployment history from the LinkedIn overlay, newest first. Empty for any developer we hold no LinkedIn match for, which is most of them.
max 25 itemstitlestring | nullJob title, on an experience entry.
max 200 charscompanystring | nullEmployer name, on an experience entry.
max 200 charsschoolstring | nullInstitution name, on an education entry.
max 200 charsdegreestring | nullDegree awarded, on an education entry.
max 200 charsfieldOfStudystring | nullField of study, on an education entry.
max 200 charsstartDatestring | nullStart date exactly as the source rendered it. Free text, NOT a normalised date: expect "2019", "Jan 2019" and "2019-01" from different records. Parse defensively.
max 200 charsendDatestring | nullEnd date in the same unnormalised free-text form as `startDate`. Absent or null on a current role.
max 200 charscurrentboolean | nullThe source's own "still there" flag. Set on experience entries; null on education entries.
educationarray of object requiredEducation history from the LinkedIn overlay. Empty for any developer we hold no LinkedIn match for.
max 25 itemstitlestring | nullJob title, on an experience entry.
max 200 charscompanystring | nullEmployer name, on an experience entry.
max 200 charsschoolstring | nullInstitution name, on an education entry.
max 200 charsdegreestring | nullDegree awarded, on an education entry.
max 200 charsfieldOfStudystring | nullField of study, on an education entry.
max 200 charsstartDatestring | nullStart date exactly as the source rendered it. Free text, NOT a normalised date: expect "2019", "Jan 2019" and "2019-01" from different records. Parse defensively.
max 200 charsendDatestring | nullEnd date in the same unnormalised free-text form as `startDate`. Absent or null on a current role.
max 200 charscurrentboolean | nullThe source's own "still there" flag. Set on experience entries; null on education entries.
professionalobject | nullLinkedIn-sourced professional scalars, present only when we hold a LinkedIn match for this developer. Absent or null for the majority of developers, which says nothing about their employment — only that we hold no overlay.
headlinestring | null requiredThe LinkedIn headline, verbatim.
max 5000 charstitlestring | null requiredCurrent job title per LinkedIn, e.g. "Chief Technology Officer".
max 200 charscompanystring | null requiredCurrent employer per LinkedIn. Distinct from the GitHub-sourced `organization` field, and the two disagree often — LinkedIn is usually the fresher of the two.
max 200 charssenioritystring | null requiredA coarse seniority label from the LinkedIn overlay ("c-level", "senior", …). Free text from the source, not a Vamo enum; do not switch on the exact string.
max 200 charsexpertisearray of string requiredSelf-declared skill tags from the LinkedIn profile. Claimed, not demonstrated — the demonstrated equivalent is the repositories under `repos` and `evidence`.
max 25 items
scorenumber | null requiredThe PAGE-LOCAL ordering key this page was sorted by, descending. It is NOT match quality and must not be shown or thresholded as one — read `relevance` for that. It is comparable only within this page: two rows from different pages, rounds, or queries cannot be compared, and the same developer can score differently on two runs. Most of the composite is about the developer regardless of your query (owns any repo, star band, whether a LinkedIn profile and devrank exist, contribution volume when the activity gate ran, minus a flat penalty for trophy accounts). A nonsense query that returns five people still scores them, so a high score means "the best of what came back", never "this matches what you asked for". Read `evidence.matchStatus` for query attribution. Null only when the producer did not rank (an older cached page).
relevancenumber | nullTHE PROVIDER’S OWN QUERY-MATCH RELEVANCE — the number to build a quality gate on, and the one `score` is not. It is the search index’s score for this row against this query. READ IT WITH the response’s `relevanceOrder`, which says whether higher or lower is better on this page: the direction INVERTS by lane, because the User lane has no vector and ranks by weighted BM25 (unbounded, higher is better) while the LinkedIn lane ranks by cosine distance (0..1, lower is better). It is comparable BETWEEN ROWS OF ONE QUERY, which is exactly what a threshold-based gate needs, and NOT across queries — BM25 magnitude moves with term rarity and with how many fields matched, so a rare token in a nonsense query can still score high on the one row containing it. Threshold on a fraction of the best row rather than an absolute constant. On the repo→contributor fanout lane it is the best-matching repo you built, which is that lane’s whole thesis for why you match. Null only when the lane that answered has no query to be relevant to at all: the repo seed gate, and any filter-only search, where the index ordered by recency instead of by match.
evidenceobjectThe proof-of-work and query-attribution block for this developer. Populated on every result from a live search; absent on pages served from an older cache.
statusstring requiredWhether we could assemble proof of work for this developer at all. `attached` = `topRepos` is populated. `partial` = some of it was assembled. `missing` = none was, and `reason` says why. A `missing` block is always explicit; an empty evidence block is never returned silently.
attachedpartialmissingreasonstring | null requiredWhy the proof-of-work block is not fully `attached`. `no_owned_repos` = this developer owns no public repositories. `not_hydrated` = we did not fetch their repositories on this call. `enrichment_failed` = the fetch was attempted and failed. Null when `status` is `attached`.
enrichment_failedno_owned_reposnot_hydratedmatchStatusstringWhether `matchedRepos` genuinely answers "why did this person come back for my query". `attributed` = it does, and every entry carries a `via`. `unattributed` = the lane that produced this result cannot attribute repositories to the query, `matchedRepos` is empty, and you MUST NOT present `topRepos` to a user as if it were the reason they matched. Absent means `unattributed`.
attributedunattributedmatchedReposarray of object requiredThe repositories that connect this developer to your query. Empty whenever `matchStatus` is `unattributed`; non-empty whenever it is `attributed`.
max 12 itemsfullNamestring requiredGitHub `owner/name`. The join key onto `developer.repos[].fullName`, so you can match an evidence repo back to the profile repo it refers to.
max 160 charsstarsinteger requiredStargazer count at retrieval time. 0 also means "the source returned no count", so do not read 0 as proof the repo is unstarred.
min 0, max 100000000languagestring | nullGitHub’s primary language for the repository. Null when none was returned; never inferred from the code. Absent on pages produced before this field existed.
max 200 charsrolestring | nullThis person’s relationship to the repository, and it is deliberately conservative. `owner` means the repository sits under THEIR namespace. `contributor` means everything else, including the person who wrote most of the code in someone else’s or an organisation’s repository — a top committer on a company repo is a `contributor`, so do not read `contributor` as "minor" or `owner` as "wrote it". Null means the lane that produced this row genuinely cannot tell; absent means an older producer did not emit the field.
ownercontributorviastringHow this repository entered the evidence block, i.e. its PROVENANCE. It is NOT a statement about which of your search terms matched. `semantic` = the prose repo search returned it for the query. `seed` = you named this repository yourself (`levers.github.similarRepos` in exact mode, or `contributedRepos`) and this person commits to it. `owned` = it is one of their top owned repositories, included as background — `owned` appears only in `topRepos` and never in `matchedRepos`. Treat an unrecognised value as unknown provenance; new members may be added.
semanticseedownedsimilaritynumber | nullHow closely THIS repository matched the query, as a cosine DISTANCE: LOWER IS CLOSER, and it is comparable between the matched repos of one result rather than across queries. Populated only on the repo→contributor fanout, where the query matched the repository and the index scores it (`via: "semantic"`). Null everywhere else — the repo-seed gate has no query to be close to, and a repo the index scored nothing for reports null rather than a synthesized number. It is NOT the developer's relevance; read `results[].relevance` with `relevanceOrder` for that.
whystring | nullReserved and always null. Retained for wire compatibility during a rollout; do not read it.
max 5000 chars
topReposarray of object requiredThe developer’s strongest owned repositories, as background proof of work. These are NOT query matches — a repository here says the person builds, not that they build what you asked for.
max 12 itemsfullNamestring requiredGitHub `owner/name`. The join key onto `developer.repos[].fullName`, so you can match an evidence repo back to the profile repo it refers to.
max 160 charsstarsinteger requiredStargazer count at retrieval time. 0 also means "the source returned no count", so do not read 0 as proof the repo is unstarred.
min 0, max 100000000languagestring | nullGitHub’s primary language for the repository. Null when none was returned; never inferred from the code. Absent on pages produced before this field existed.
max 200 charsrolestring | nullThis person’s relationship to the repository, and it is deliberately conservative. `owner` means the repository sits under THEIR namespace. `contributor` means everything else, including the person who wrote most of the code in someone else’s or an organisation’s repository — a top committer on a company repo is a `contributor`, so do not read `contributor` as "minor" or `owner` as "wrote it". Null means the lane that produced this row genuinely cannot tell; absent means an older producer did not emit the field.
ownercontributorviastringHow this repository entered the evidence block, i.e. its PROVENANCE. It is NOT a statement about which of your search terms matched. `semantic` = the prose repo search returned it for the query. `seed` = you named this repository yourself (`levers.github.similarRepos` in exact mode, or `contributedRepos`) and this person commits to it. `owned` = it is one of their top owned repositories, included as background — `owned` appears only in `topRepos` and never in `matchedRepos`. Treat an unrecognised value as unknown provenance; new members may be added.
semanticseedownedsimilaritynumber | nullHow closely THIS repository matched the query, as a cosine DISTANCE: LOWER IS CLOSER, and it is comparable between the matched repos of one result rather than across queries. Populated only on the repo→contributor fanout, where the query matched the repository and the index scores it (`via: "semantic"`). Null everywhere else — the repo-seed gate has no query to be close to, and a repo the index scored nothing for reports null rather than a synthesized number. It is NOT the developer's relevance; read `results[].relevance` with `relevanceOrder` for that.
whystring | nullReserved and always null. Retained for wire compatibility during a rollout; do not read it.
max 5000 chars
401No or invalid credentialcodestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.
402Plan lacks search:deep, insufficient balance, or budgetCredits is below this job’s estimatecodestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.
403Missing search:deep (role)codestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.
429Job-submit rate limit or DeepSearches quota exhaustedcodestring requiredStable machine-readable error code. Branch on this, never on the numeric status.
bad_requestunauthorizedsignature_requiredpayment_requiredforbiddennot_foundconflictgonepayload_too_largeunprocessable_entitytoo_many_requestsinternal_errornot_implementedbilling_unavailablenot_contactablemailbox_link_unavailablemailbox_requiredmail_engine_unavailablewebhook_publisher_unavailabledatabase_unavailableclient_errormessagestring requiredHuman-readable explanation of the refusal.
statusinteger requiredThe HTTP status code, repeated in the body.
remedyobjectA self-serve path forward, when one exists (a 402 points at the credit top-up).
kindstring requiredWhat kind of remedy this is, so a client can route it: whether the caller can clear the condition through the API, or a person must act in the web app.
topupconnect_mailboxurlstring requiredWhere to go to clear the condition: an API path, or a web app page when only a person can.