Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/githunt-ai:githunt-ai-briefs-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: GitHunt Briefs API
version: 1.0.0
description: 'Search, look up, and analyze GitHub developers programmatically. GitHunt gives you millisecond access to millions of developers available on GitHub - ranked, scored, and with contact details where publicly available. Every request is billed against your plan''s monthly API call quota; all plans are additionally capped at 2000 calls/day.
Quotas: Free 50 calls/month (trial), Pro 1000 calls/month, Team 1500 calls/month (unused credits roll over, up to one extra month''s allowance), Enterprise unlimited. Endpoints cost different amounts of quota: search 1 credit, get user 1 credit, evidence report 3 credits (0 when the report is still pending), analyze profile 3 credits, and every /v1/lists operation 0 credits. Endpoints that debit 0 credits still count against the daily cap.'
contact:
email: support@githunt.ai
servers:
- url: https://api.githunt.ai
security:
- bearerAuth: []
- apiKeyAuth: []
tags:
- name: Briefs
paths:
/v1/briefs:
post:
operationId: createBrief
summary: Submit a sourcing brief and run it server-side
description: 'Runs a whole sourcing brief on the server instead of making the caller orchestrate dozens of searches and evidence polls. The run expands the requested regions into countries, searches them three at a time against the candidate pool, ranks the union, gathers evidence reports for a bounded shortlist, and splits the shortlist into delivered profiles and screening leads. Countries your exclusions would discard anyway are skipped before any search runs, and listed in `coverage.countries_skipped`.
Returns `202` with a `brief_id` immediately; poll `GET /v1/briefs/{brief_id}` for the result. Debits 25 credits once, at submission: about fifteen pool searches plus up to twenty-five evidence builds reused from the shared cache, priced below the sum of the equivalent `search` and `evidence` calls. Polling is free of monthly credits. A `400` is uncharged.
A brief may name up to six `regions`, more than one search request may carry, because it expands and batches its own geography. Every criteria and exclusion field is validated by the same rules `POST /v1/search` applies, and every ceiling in the run is server-controlled.
Public evidence can never establish commercial tenure, employment, or any closed-source work. A delivered profile means a stated location that resolved to a single country offset plus at least one inspected, candidate-authored in-window commit in a requested skill; everything else is a screening lead with a stated reason.'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BriefRequest'
responses:
'202':
description: Brief accepted and queued (debits 25 credits)
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before the first poll
content:
application/json:
schema:
$ref: '#/components/schemas/BriefAcceptedResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'429':
$ref: '#/components/responses/QuotaExceeded'
'500':
$ref: '#/components/responses/InternalError'
tags:
- Briefs
/v1/briefs/{briefId}:
get:
operationId: getBrief
summary: Poll a sourcing brief
description: 'Returns the brief''s status and progress while it runs, and the full result once it is `complete` or `partial`. `partial` means the whole brief did not run: a ceiling was hit (search calls or time budget), a batch held more ranked rows than the run could read (`coverage.truncated`), or evidence was still building. Report the regions actually covered rather than claiming exhaustive coverage. Debits 0 monthly credits; every call still passes the daily cap. Only the account that submitted the brief can read it; anyone else gets the same `404` as a brief that does not exist.'
parameters:
- name: briefId
in: path
required: true
schema:
type: string
format: uuid
description: The `brief_id` returned by `POST /v1/briefs`
responses:
'200':
description: Brief status. Carries `result` when `status` is `complete` or `partial`, and `retry_after_seconds` while it is still running.
headers:
Retry-After:
schema:
type: integer
description: Present while the brief is still running
content:
application/json:
schema:
$ref: '#/components/schemas/BriefStatusResponse'
'400':
$ref: '#/components/responses/BadRequest'
'401':
$ref: '#/components/responses/Unauthorized'
'404':
$ref: '#/components/responses/NotFound'
'429':
$ref: '#/components/responses/QuotaExceeded'
'500':
$ref: '#/components/responses/InternalError'
tags:
- Briefs
components:
responses:
InternalError:
description: Unexpected server error
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
Unauthorized:
description: Missing, invalid, or revoked API key
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
QuotaExceeded:
description: Monthly or daily quota exceeded
headers:
Retry-After:
schema:
type: integer
description: Seconds until the quota resets
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
NotFound:
description: No matching developer
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
BadRequest:
description: Invalid request
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
schemas:
ErrorResponse:
type: object
required:
- success
- error
properties:
success:
type: boolean
const: false
error:
type: object
required:
- code
- message
properties:
code:
type: string
enum:
- unauthorized
- quota_exceeded
- invalid_request
- not_found
- internal
message:
type: string
BriefAcceptedResponse:
type: object
properties:
success:
type: boolean
const: true
data:
type: object
properties:
brief_id:
type: string
format: uuid
status:
type: string
const: queued
retry_after_seconds:
type: integer
description: Matches the `Retry-After` header. Do not poll faster.
meta:
$ref: '#/components/schemas/Meta'
BriefCard:
type: object
description: One evidence-backed profile. Identity, verified skill evidence, public commercial signals, domain evidence, and a screening question for every unknown. Every status and reason comes from the same criterion rules `GET /v1/users/{login}/evidence` applies.
properties:
login:
type: string
name:
type: string
nullable: true
location:
type: string
nullable: true
location_resolution:
type: object
nullable: true
description: How the stated base resolved at the run timestamp. Only `resolved` can be delivered; `ambiguous` and `unresolved` are screening leads.
properties:
status:
type: string
enum:
- resolved
- ambiguous
- unresolved
country:
type: string
nullable: true
utc_offset:
type: object
nullable: true
basis:
type: string
nullable: true
screening_reason:
type: string
nullable: true
observed_at:
type: string
company:
type: string
nullable: true
bio:
type: string
nullable: true
hireable:
nullable: true
profile_url:
type: string
score:
type: number
nullable: true
rank_breakdown:
type: object
nullable: true
description: Why the ranker placed this row where it did. Present when the brief named languages, skills, sectors, organizations or domains.
properties:
base:
type: number
description: Score before the evidence multipliers.
recency:
type: number
org:
type: number
domain:
type: number
final:
type: number
description: The value the ordering actually used.
discovered_by:
type: array
items:
type: string
description: Which location batches surfaced this candidate.
evidence_status:
type: string
enum:
- cached
- built
- pending
- skipped
evaluated_at:
type: string
nullable: true
window:
type: object
nullable: true
coverage:
type: object
nullable: true
description: The evidence scan's own coverage, as on the evidence endpoint.
criteria:
type: object
nullable: true
description: The evidence report's criterion assessments, verbatim.
skill_evidence:
type: object
properties:
status:
type: string
reason:
type: string
nullable: true
inspected_in_window:
type: integer
description: Inspected candidate-authored in-window commits in a requested skill. One or more is what makes a card deliverable.
last_commit:
type: string
nullable: true
repos:
type: array
items:
type: object
properties:
repository:
type: string
url:
type: string
owner_type:
type: string
nullable: true
commits_seen:
type: integer
commits_in_window:
type: integer
inspected:
type: integer
last_commit:
type: string
nullable: true
commits:
type: array
items:
type: object
properties:
url:
type: string
nullable: true
date:
type: string
nullable: true
message:
type: string
nullable: true
repository:
type: string
nullable: true
files_changed:
type: integer
nullable: true
code_languages:
type: array
items:
type: string
commercial_signals:
type: object
description: Public context for paid work, never a tenure claim. `tenure_status` is `unknown` unless a dated, corroborated interval exists.
properties:
public_signals_only:
type: boolean
const: true
tenure_status:
type: string
tenure_reason:
type: string
nullable: true
items:
type: array
items:
type: object
properties:
type:
type: string
enum:
- public_org_contribution
- self_reported_employment
- commit_email_domain
value:
type: string
url:
type: string
nullable: true
organization:
type: string
nullable: true
company:
type: string
nullable: true
interval:
type: object
nullable: true
commits:
type: integer
nullable: true
active_years:
type: array
items:
type: integer
languages:
type: array
items:
type: string
domain_evidence:
type: object
properties:
tier:
type: string
enum:
- core
- adjacent
- generic
- none
description: '`core` only when the evidence report''s `core_domain_recent` criterion is supported. A core term in a README or a commit subject is context and lands as `adjacent` at best.'
status:
type: string
reason:
type: string
nullable: true
subsystems:
type: array
items:
type: string
items:
type: array
items:
type: object
properties:
url:
type: string
nullable: true
date:
type: string
nullable: true
term:
type: string
pack:
type: string
subsystem:
type: string
nullable: true
context:
type: string
nullable: true
kind:
type: string
repository:
type: string
nullable: true
screening_questions:
type: array
items:
type: string
links:
type: object
properties:
profile:
type: string
blog:
type: string
twitter:
type: string
BriefRequest:
type: object
required:
- criteria
- geography
properties:
criteria:
type: object
description: What the candidate must be. At least one language or skill is needed for evidence to be gathered.
properties:
languages:
type: array
items:
type: string
example:
- Scala
skills:
type: array
items:
type: string
role:
type: string
description: Role profile to score against, same list as `POST /v1/search`.
sectors:
type: array
items:
type: string
description: Employer sectors to favour via the employer graph, max 5.
domains:
type: array
items:
type: string
example:
- payments
description: Domain packs to assess core subject-matter work against, max 3. Without a domain every card comes back with domain tier `none`.
skillRecency:
type: array
description: Hard eligibility filter on evidenced skill recency, same shape as search.
items:
type: object
properties:
skill:
type: string
minActiveYears:
type: number
usedWithinYears:
type: number
geography:
type: object
description: Where to look, and where not to. At least one of `regions` or `locations` is required.
properties:
regions:
type: array
maxItems: 6
items:
type: string
example:
- north-america
- latin-america
description: Regions to cover, max 6 - more than a single search request may carry. Each expands into countries searched three at a time, so every country gets the ranker's full scoring depth.
locations:
type: array
maxItems: 20
items:
type: string
excludeLocations:
type: array
items:
type: string
example:
- India
excludeUtcOffsets:
type: object
description: 'Inclusive UTC offset band to exclude at the run timestamp, with DST applied. `{min: 0, max: 5}` leaves +5:30 and +5:45 eligible.'
properties:
min:
type: number
max:
type: number
includeUnlocated:
type: boolean
description: Include candidates with no stated location. They can never be delivered, only surfaced as screening leads.
deliver:
type: object
properties:
maxProfiles:
type: integer
minimum: 1
maximum: 25
default: 10
maxScreeningLeads:
type: integer
minimum: 0
maximum: 50
default: 15
evidence:
type: boolean
default: true
description: Gather evidence reports for the shortlist. With `false` the run is faster but no profile carries verified commits, so every result is a lead.
Quota:
type: object
properties:
used:
type: integer
limit:
type: integer
description: -1 means unlimited
month:
type: string
example: 2026-07
cost:
type: integer
description: 'Credits this request debited (search: 1, get user: 1, evidence report: 3 when a report is returned and 0 while pending, analyze profile: 3, list operations: 0). `used` already reflects this charge.'
example: 1
rollover:
type: integer
description: Unused credits banked from the previous month and available on top of `limit` this month (`remaining` = limit + rollover - used). Only present on the Team plan, capped at one extra month's allowance (so at most 2x the allowance is usable in a month).
example: 340
Meta:
type: object
description: Envelope metadata. `quota.cost` is 0 on endpoints that debit no credits.
properties:
requestId:
type: string
quota:
$ref: '#/components/schemas/Quota'
BriefStatusResponse:
type: object
properties:
success:
type: boolean
const: true
data:
type: object
properties:
brief_id:
type: string
format: uuid
status:
type: string
enum:
- queued
- running
- complete
- partial
- failed
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
progress:
type: object
description: Live counters while the run is in flight.
properties:
phase:
type: string
enum:
- queued
- search
- evidence
- done
- failed
searches_done:
type: integer
searches_planned:
type: integer
candidates:
type: integer
shortlisted:
type: integer
evidence_ready:
type: integer
evidence_pending:
type: integer
retry_after_seconds:
type: integer
description: Present while the brief is still running.
error:
type: string
description: Present when `status` is `failed`.
result:
$ref: '#/components/schemas/BriefResult'
meta:
$ref: '#/components/schemas/Meta'
BriefResult:
type: object
description: Present once the brief is `complete` or `partial`.
properties:
cover:
type: object
description: The brief as run, plus the assumptions every claim below rests on.
properties:
brief_id:
type: string
prepared_at:
type: string
format: date-time
criteria:
type: object
geography:
type: object
assumptions:
type: array
items:
type: string
delivered:
type: integer
screening_leads:
type: integer
requested_profiles:
type: integer
summary:
type: array
description: One row per delivered profile, in delivery order.
items:
type: object
properties:
rank:
type: integer
login:
type: string
name:
type: string
nullable: true
location:
type: string
nullable: true
utc_offset:
type: object
nullable: true
last_skill_commit:
type: string
nullable: true
inspected_in_window:
type: integer
domain_tier:
type: string
enum:
- core
- adjacent
- generic
- none
tenure_status:
type: string
screening_questions:
type: integer
recency:
type: number
nullable: true
description: The recency multiplier from `rank_breakdown`.
org:
type: number
nullable: true
domain:
type: number
nullable: true
profiles:
type: array
items:
$ref: '#/components/schemas/BriefCard'
screening_leads:
type: array
description: Cards that did not meet a delivery rule, each with a `reason`. Overflow beyond `maxProfiles` appears here too.
items:
allOf:
- $ref: '#/components/schemas/BriefCard'
- type: object
properties:
reason:
type: string
coverage:
type: object
description: What was actually searched. Never a claim of worldwide coverage.
properties:
regions_requested:
type: array
items:
type: string
countries_searched:
type: array
items:
type: string
countries_skipped:
type: array
description: Countries the region expansion produced that the brief would have discarded anyway, so no search was spent on them.
items:
type: object
properties:
country:
type: string
reason:
type: string
enum:
- excluded_location
- utc_offset_band
description: '`excluded_location` - named in `excludeLocations`. `utc_offset_band` - the country''s whole UTC range sits inside `excludeUtcOffsets` at the run timestamp. A country only partly inside the band is still searched.'
batches_planned:
type: integer
batches_run:
type: integer
search_calls:
type: integer
candidate_rows:
type: integer
description: Rows returned before dedup, the denominator for a duplicate rate.
unique_candidates:
type: integer
shortlisted:
type: integer
evidence:
type: object
properties:
cached:
type: integer
built:
type: integer
pending:
type: integer
skipped:
type: integer
truncated:
type: boolean
description: A batch's ranking held more rows than the run could read, so some ranked candidates were never seen.
retrieval_capped:
type: boolean
description: 'True when the ranker''s per-location retrieval ceiling was reached for at least one country: more candidates may exist there than this run could read. A capped read is not an incomplete run - absence under a cap is not evidence of absence - and it does not by itself make `status` `partial`.'
partial:
type: boolean
description: True when a ceiling was hit, a batch was truncated, or evidence was still building. `status` is `partial` exactly when this is. A per-location retrieval cap is reported separately as `retrieval_capped`.
stopped_reason:
type: string
nullable: true
enum:
- search_call_ceiling
- time_budget
- null
batches:
type: array
items:
type: object
note:
type: string
manifest:
type: object
description: Everything needed to reproduce or compare two runs.
properties:
brief_id:
type: string
run_started_at:
type: string
format: date-time
run_completed_at:
type: string
format: date-time
skills:
type: array
items:
type: string
domains:
type: array
items:
type: string
evidence_requested:
type: boolean
evidence_cache_key:
type: string
nullable: true
evidence_schema_version:
type: integer
inspection_rules_version:
type: integer
ceilings:
type: object
securitySchemes:
bearerAuth:
type: http
scheme: bearer
description: 'Authorization: Bearer ghk_live_...'
apiKeyAuth:
type: apiKey
in: header
name: X-Api-Key