API reference navigation
POST /v1/searches/angles

Angles to Search GitHub with

Access
Authenticated
search:read
Cost
Free
Rate limit
60 / minute per account
Quota
None

Suggested angles: each one is a complete query to Search GitHub with, plus the SearchConfigV2 seed to adopt and edit. Pass scope: account for the company's opening angles (its topics, peer companies, stack and metro) or scope: project with a projectId for three angles on that role, drawn from its topics, the repos and companies it points at, and the work it contributes to, with a bare language angle only as a last resort: both are generated once per change to the underlying context, cached, and free to read, with regenerate: true forcing a fresh set. Pass a compiled SearchConfigV2 or a job description instead to derive angles for that brief alone, never from a shortlist.

Request body SearchAnglesRequest

  • scope string

    Derive angles from stored context instead of a brief. `account` reads your company profile (its topics, peer companies, stack and location); `project` reads one role’s own settings. Both are generated once per context change, cached, and free to read, so there is no model call per page load.

    accountproject
  • projectId string

    Which project’s settings to read. Required with `scope: project`.

    max 16 chars
  • regenerate boolean

    Ignore the cached wording and write a fresh set. Use sparingly: the cache is what keeps this free and instant.

  • config object

    An already-compiled search config, for example from `POST /v1/searches/compile`. Angles are then derived from it deterministically, with no model call at all.

    • version number required

      Marks this as a version 2 config. The only required field alongside `query`.

      2
    • query string | null required

      Free-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 chars
    • entity string 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.

      autoUserRepoLinkedInUser
    • requiredLanguages array 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 items
    • earlyCareerSignals boolean default: false

      Bias 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.

    • aiFocusedSignals boolean default: false

      Bias every angle toward AI, agent, LLM, retrieval and inference work.

    • includeUnconventionalTitles boolean default: false

      Keep 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.

    • levers object 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.

      • skills array 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 items
      • interests array 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 items
      • technologies array of string

        Languages, 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 items
      • location object

        Where the person is. Every location signal here is SELF-REPORTED by the developer and never verified.

        • countries array of string default: []

          Countries, matched against our geocoding of the self-reported location.

          max 20 items
        • cities array of string default: []

          Cities, matched against our geocoding of the self-reported location.

          max 20 items
        • states array of string default: []

          States or regions, matched against our geocoding.

          max 20 items
        • raw array of string default: []

          Raw location strings, matched against what the developer literally typed on GitHub.

          max 20 items
        • strict boolean

          True 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.

      • requireLinkedin boolean

        Return 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.

      • openToWork boolean

        Restrict to people flagged as open to work on their LinkedIn profile. Requires the LinkedIn overlay, so it implies the same narrowing as `requireLinkedin`.

      • experienceTier string

        A coarse experience band to aim at.

        earlyupToSeniorseniorall
      • yoeRange object

        A years-of-experience band, derived from the LinkedIn overlay, so it only constrains people we hold one for.

        • min integer | null required

          Minimum years of experience. Null for no lower bound.

          min 0
        • max integer | null required

          Maximum years of experience. Null for no upper bound.

          min 0
      • professional object

        Employment 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.

        • currentCompanies array of string default: []

          Companies the person works at NOW.

          max 20 items
        • pastCompanies array of string default: []

          Companies the person used to work at.

          max 20 items
        • mustHaveWorkedAt array 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 items
        • excludeCurrentCompanies array 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 items
        • schools array of string default: []

          Institutions the person attended.

          max 20 items
        • titles array of string default: []

          Job titles to aim at.

          max 20 items
        • industries array of string default: []

          Industries the person works in.

          max 20 items
        • companySizeTier string

          The size band of the person’s current employer.

          1-5051-200201-20002000+
        • companiesMode string

          How the company lists bind. `exact` matches the named companies only. `similar` expands them to comparable companies, which widens reach at the cost of precision.

          exactsimilar
        • similarCompanies array of string default: []

          Companies to treat as reference points for "companies like these", rather than as an allowlist in themselves.

          max 20 items
        • includePast boolean

          Match against the full employment history rather than the current employer only. Defaults to true.

      • github object

        GitHub-side levers: stars, followers, seed repositories, and the devrank floor.

        • starRange object | null default: null

          A star band on the person’s repositories. Null, the default, means no bound at all rather than a missing value.

          • min integer | null required

            Lower bound, inclusive. Null for no lower bound.

            min 0
          • max integer | null required

            Upper bound, inclusive. Null for no upper bound.

            min 0
        • similarRepos array of string default: []

          Seed repositories, as `owner/name`. How they bind depends on `repoMode`: expanded to similar repositories, or matched exactly.

          max 20 items
        • contributedRepos array 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 items
        • minDevrank integer | null default: null

          A 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 100
        • hideHighProfile boolean

          Suppress very high-profile accounts, which otherwise dominate a ranking without being realistic hires.

        • repoMode string default: "similar"

          How `similarRepos` binds. `similar`, the default, expands each seed to comparable repositories. `exact` matches only the repositories you named.

          similarexact
        • followerRange object | null

          A band on GitHub follower count. Null bounds mean no limit on that side.

          • min integer | null required

            Lower bound, inclusive. Null for no lower bound.

            min 0
          • max integer | null required

            Upper bound, inclusive. Null for no upper bound.

            min 0
        • minContributionsLastYear integer | null

          THE 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 100000
        • minContributionsLastMonth integer | null

          The 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
    • filter object

      A raw filter expression, as an escape hatch for constraints the levers do not express. Opaque here and validated by the compiler; prefer the levers.

    • boost array 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 items
      • signal string required

        The signal to weight. Read `GET /v1/search/capabilities` for the signals that exist and whether each can be pushed to the index.

        max 200 chars
      • weight number required

        Its weight. Positive favours the signal, negative penalises it.

    • rank object

      How 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.

      • preset string

        A named ranking preset.

        max 200 chars
      • weights array of object

        Explicit per-signal weights, as an alternative to a preset.

        max 20 items
        • signal string required

          The signal to weight.

          max 200 chars
        • weight number required

          Its weight.

  • jd string | null

    A pasted job description. Runs the role extractor when no `config` is given.

    max 50000 chars
  • prompt string | null

    Free-text steering, folded into the extractor input.

    max 50000 chars

Responses

  • 200 The suggested angles
    • suggestions array of SearchSuggestion required

      The angles as structured suggestions, each with a partial config seed you can adopt and edit.

      max 20 items
      • id string required

        Identifier for this suggestion, stable within the response.

      • label string required

        A short name for the angle, for a picker.

      • description string required

        What this angle looks for and why it might be worth trying.

      • config object required

        A PARTIAL search config seeding this angle. Merge it into your own config, edit the levers, then execute — it is a starting point, not a runnable config on its own.

        • version number

          Marks this as a version 2 config. The only required field alongside `query`.

          2
        • query string | null

          Free-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 chars
        • entity string 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.

          autoUserRepoLinkedInUser
        • requiredLanguages array 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 items
        • earlyCareerSignals boolean default: false

          Bias 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.

        • aiFocusedSignals boolean default: false

          Bias every angle toward AI, agent, LLM, retrieval and inference work.

        • includeUnconventionalTitles boolean default: false

          Keep 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.

        • levers object 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.

          • skills array 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 items
          • interests array 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 items
          • technologies array of string

            Languages, 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 items
          • location object

            Where the person is. Every location signal here is SELF-REPORTED by the developer and never verified.

            • countries array of string default: []

              Countries, matched against our geocoding of the self-reported location.

              max 20 items
            • cities array of string default: []

              Cities, matched against our geocoding of the self-reported location.

              max 20 items
            • states array of string default: []

              States or regions, matched against our geocoding.

              max 20 items
            • raw array of string default: []

              Raw location strings, matched against what the developer literally typed on GitHub.

              max 20 items
            • strict boolean

              True 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.

          • requireLinkedin boolean

            Return 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.

          • openToWork boolean

            Restrict to people flagged as open to work on their LinkedIn profile. Requires the LinkedIn overlay, so it implies the same narrowing as `requireLinkedin`.

          • experienceTier string

            A coarse experience band to aim at.

            earlyupToSeniorseniorall
          • yoeRange object

            A years-of-experience band, derived from the LinkedIn overlay, so it only constrains people we hold one for.

            • min integer | null required

              Minimum years of experience. Null for no lower bound.

              min 0
            • max integer | null required

              Maximum years of experience. Null for no upper bound.

              min 0
          • professional object

            Employment 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.

            • currentCompanies array of string default: []

              Companies the person works at NOW.

              max 20 items
            • pastCompanies array of string default: []

              Companies the person used to work at.

              max 20 items
            • mustHaveWorkedAt array 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 items
            • excludeCurrentCompanies array 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 items
            • schools array of string default: []

              Institutions the person attended.

              max 20 items
            • titles array of string default: []

              Job titles to aim at.

              max 20 items
            • industries array of string default: []

              Industries the person works in.

              max 20 items
            • companySizeTier string

              The size band of the person’s current employer.

              1-5051-200201-20002000+
            • companiesMode string

              How the company lists bind. `exact` matches the named companies only. `similar` expands them to comparable companies, which widens reach at the cost of precision.

              exactsimilar
            • similarCompanies array of string default: []

              Companies to treat as reference points for "companies like these", rather than as an allowlist in themselves.

              max 20 items
            • includePast boolean

              Match against the full employment history rather than the current employer only. Defaults to true.

          • github object

            GitHub-side levers: stars, followers, seed repositories, and the devrank floor.

            • starRange object | null default: null

              A star band on the person’s repositories. Null, the default, means no bound at all rather than a missing value.

            • similarRepos array of string default: []

              Seed repositories, as `owner/name`. How they bind depends on `repoMode`: expanded to similar repositories, or matched exactly.

              max 20 items
            • contributedRepos array 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 items
            • minDevrank integer | null default: null

              A 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 100
            • hideHighProfile boolean

              Suppress very high-profile accounts, which otherwise dominate a ranking without being realistic hires.

            • repoMode string default: "similar"

              How `similarRepos` binds. `similar`, the default, expands each seed to comparable repositories. `exact` matches only the repositories you named.

              similarexact
            • followerRange object | null

              A band on GitHub follower count. Null bounds mean no limit on that side.

            • minContributionsLastYear integer | null

              THE 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 100000
            • minContributionsLastMonth integer | null

              The 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
        • filter object

          A raw filter expression, as an escape hatch for constraints the levers do not express. Opaque here and validated by the compiler; prefer the levers.

        • boost array 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 items
          • signal string required

            The signal to weight. Read `GET /v1/search/capabilities` for the signals that exist and whether each can be pushed to the index.

            max 200 chars
          • weight number required

            Its weight. Positive favours the signal, negative penalises it.

        • rank object

          How 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.

          • preset string

            A named ranking preset.

            max 200 chars
          • weights array of object

            Explicit per-signal weights, as an alternative to a preset.

            max 20 items
            • signal string required

              The signal to weight.

              max 200 chars
            • weight number required

              Its weight.

    • angles array of string required

      The same angles as plain strings, for display where the config seed is not needed.

      max 20 items
    • pending boolean required

      True when fresh wording is still being generated for this context, in which case what you are reading is the deterministic fallback that it will replace — read again shortly for the final set. Always false on the config and brief paths, which never generate.

  • 401 No or invalid credential
    • code string required

      Stable 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_error
    • message string required

      Human-readable explanation of the refusal.

    • status integer required

      The HTTP status code, repeated in the body.

    • remedy object

      A self-serve path forward, when one exists (a 402 points at the credit top-up).

      • kind string required

        What 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_mailbox
      • url string required

        Where to go to clear the condition: an API path, or a web app page when only a person can.

  • 403 Missing search:read
    • code string required

      Stable 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_error
    • message string required

      Human-readable explanation of the refusal.

    • status integer required

      The HTTP status code, repeated in the body.

    • remedy object

      A self-serve path forward, when one exists (a 402 points at the credit top-up).

      • kind string required

        What 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_mailbox
      • url string required

        Where to go to clear the condition: an API path, or a web app page when only a person can.

  • 404 No such project in this account
    • code string required

      Stable 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_error
    • message string required

      Human-readable explanation of the refusal.

    • status integer required

      The HTTP status code, repeated in the body.

    • remedy object

      A self-serve path forward, when one exists (a 402 points at the credit top-up).

      • kind string required

        What 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_mailbox
      • url string required

        Where to go to clear the condition: an API path, or a web app page when only a person can.