# AYHire API Documentation

## Base URL

```
http://localhost:3000/api
```

---

## Endpoints

### POST /api/analyze

Analyze a single GitHub user. Scrapes their profile, scores them with Claude, generates embeddings.

**Request:**
```json
{
  "username": "sindresorhus"
}
```

**Response:**
```json
{
  "candidate": {
    "id": "uuid",
    "github_username": "sindresorhus",
    "name": "Sindre Sorhus",
    "scores": {
      "technical_depth": 10,
      "shipping_velocity": 9,
      "stack_match": 7,
      "communication": 9,
      "value": 6,
      "gem_score": 2
    },
    "summary": "Prolific open-source maintainer...",
    "top_skills": ["TypeScript", "JavaScript", "Swift", "CLI tools"],
    "red_flags": []
  }
}
```

---

### POST /api/bulk-analyze

Analyze multiple GitHub users (max 10 per request).

**Request:**
```json
{
  "usernames": ["shadcn", "leerob", "rauchg"]
}
```

**Response:**
```json
{
  "results": [
    { "username": "shadcn", "status": "success" },
    { "username": "leerob", "status": "success" },
    { "username": "rauchg", "status": "error", "error": "Rate limited" }
  ]
}
```

---

### POST /api/search

Semantic search over analyzed candidates using RAG (pgvector embeddings).

**Request:**
```json
{
  "query": "TypeScript developer who builds with Supabase and ships weekly",
  "limit": 10
}
```

**Response:**
```json
{
  "candidates": [
    {
      "id": "uuid",
      "github_username": "example",
      "name": "Dev Name",
      "scores": { ... },
      "raw_data": { "summary": "...", "top_skills": [...] },
      "search_relevance": 0.87
    }
  ],
  "query": "TypeScript developer who builds with Supabase and ships weekly"
}
```

---

### GET /api/candidates

List all analyzed candidates, paginated. Requires an API key or a session. Contact data (email) is not included.

**Query params:**
- `limit` (default: 50, max: 100)
- `offset` (default: 0)

**Response:**
```json
{
  "candidates": [...],
  "total": 142
}
```

---

### GET /api/candidates/:id

Get a candidate profile with repos. Requires an API key or a session. Contact data (email) is not included.

**Response:**
```json
{
  "candidate": {
    "id": "uuid",
    "github_username": "sindresorhus",
    "name": "Sindre Sorhus",
    "bio": "Full-Time Open-Sourcerer...",
    "location": null,
    "avatar_url": "https://...",
    "scores": { ... },
    "raw_data": { "summary": "...", "top_skills": [...], "red_flags": [...] },
    "analyzed_at": "2026-05-09T..."
  },
  "repos": [
    {
      "repo_name": "awesome",
      "language": null,
      "stars": 464513,
      "forks": 32000,
      "analysis": { "topics": [...], "url": "https://github.com/..." }
    }
  ]
}
```

---

## Roles (open positions you source for)

Agents use the MCP tools `list_roles`, `create_role`, `find_people_for_role`, `score_role_person`, `get_role`, `decide` and `get_shortlist`, and decide themselves who is worth scoring. All routes need an API key or a session.

### GET /api/roles
Your roles, newest first, with counts of picks, set aside, not looked at yet and shortlisted.

### POST /api/roles
Create a role: `{ "title": "...", "brief": "...", "search": { "mode": "repos", "query": "agent framework", "language": "Python" } }`.

### GET /api/roles/:id · PATCH /api/roles/:id · DELETE /api/roles/:id
The role and everyone in it, ranked with AyHire's call (picks, then set aside, then not looked at yet). PATCH changes the title, brief or search.

### POST /api/roles/:id/run
The whole run in one call: find the people behind matching repos, save them, then score the top people not looked at yet. Body: `{ "score_top": 5 }` (0-10). Saved analyses are free; new ones count toward the hourly limits.

### POST /api/roles/:id/search
Only the first step: find and save people. Returns `{ found, added, total, next }` (`next` = who to score next).

### POST /api/roles/:id/people/:username/score
Score one person in the role: analysis (free when saved) and an availability check. Returns the person with their call, and `limited` when an hourly cap stopped part of the work.

### PATCH /api/roles/:id/people/:username
Save your decision (`shortlisted`, `not_now`, `none`), notes, watch or contacted date.

### POST /api/roles/:id/people/:username/check
Re-check availability now (a paid lookup).

### GET /api/shortlist
Everyone you shortlisted, across roles.

---

## Scoring System (EY Talent)

| Dimension | Description | Range |
|-----------|-------------|-------|
| technical_depth | Code complexity, architecture patterns, language breadth | 0-10 |
| shipping_velocity | Push frequency, release cadence, repo freshness | 0-10 |
| stack_match | Relevance to modern stacks (TS, Next.js, Python, AI, Supabase) | 0-10 |
| communication | README quality, commit messages, issue engagement | 0-10 |
| value | Quality-to-cost ratio based on location and skill | 0-10 |
| gem_score | How undiscovered (low followers, high quality code) | 0-10 |

**Total: 60 points max**

---

## Environment Variables Required

| Variable | Description |
|----------|-------------|
| NEXT_PUBLIC_SUPABASE_URL | Supabase project URL |
| SUPABASE_SERVICE_ROLE_KEY | Supabase service role key |
| GITHUB_TOKEN | GitHub personal access token |
| ANTHROPIC_API_KEY | Anthropic API key for Claude analysis |
| VOYAGE_API_KEY | (Optional) Voyage AI key for embeddings |

---

## Rate Limits

- GitHub API: 5,000 requests/hour with token
- Claude API: depends on your Anthropic plan
- Bulk analyze: max 10 users per request (sequential to respect rate limits)
