API documentation · v2

Complete recruiter platform API reference.

These docs cover every endpoint in the V2 commerce service — authentication, semantic search, resume commerce, inbox management, access controls, and portfolio operations. Use merchant API keys (htc_...) for server-side automation and bots.

Surface Search, commerce, inbox, access
Auth Merchant API keys and browser sessions
Use case Human-readable integration reference

Base URL

https://yourdomain.hiddentalent.club

Replace with the deployed site origin that hosts your commerce APIs. All examples use $BASE_URL and $HTC_API_KEY environment variables.

Quick Setup

export BASE_URL="https://yourdomain.hiddentalent.club"
export HTC_API_KEY="htc_your_key_here"

Authentication

All authenticated endpoints require a Bearer token. Use merchant API keys (prefixed htc_) for server-side automation. Browser users authenticate via Scalekit SSO.

Merchant API key

Create keys in the Merchant Console. Keys begin with htc_. Pass them as Bearer tokens.

Authorization: Bearer htc_...

The raw secret is returned only once on creation. Store it securely.

Auth methods

  • API Keyauth_method: "api_key", actor_type: "bot"
  • Browser Sessionauth_method: "browser_session", actor_type: "user"
  • Both resolve into the same org-scoped auth context

Verify session

GET /v2/auth/session/verify

Returns the current actor's identity, organization, alias, role, portfolio context, and site config.

curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/auth/session/verify"
{
  "user_id": "user_abc123",
  "org_id": "user_abc123",
  "email": "[email protected]",
  "alias_email": "[email protected]",
  "auth_method": "api_key",
  "actor_type": "bot",
  "role": "owner",
  "portfolio": null,
  "connected": false,
  "site": { "site_name": "Hidden Talent Club", "site_tagline": "..." },
  "request_id": "req_..."
}

Upload, shortlists, wallet, claims, and owned resumes

Upload a resume

POST /v2/resumes/upload
POST /v2/public/resumes/upload

Uploads a PDF resume through the processing pipeline using the shared structured intake contract. The authenticated recruiter route preserves alias ownership and upload-credit behavior; the public route accepts open website submissions without trusting org ownership from the browser. Max size: 15 MB.

Field Type Req Description
resume file (multipart) Yes PDF file to upload
uploader_email string Yes Uploader email for the structured intake record
referrer_email string No Optional secondary referrer email if different from uploader
current_ctc string Yes Current compensation text as supplied by the uploader
expected_ctc string Yes Expected compensation text as supplied by the uploader
preferred_location string Yes Preferred job location
years_of_experience string Yes Actual years of experience entered by the uploader
custom_notes string No Free-form notes passed into resume analysis
custom_data_json string (JSON object) No Optional custom key/value metadata object
curl -X POST "$BASE_URL/v2/resumes/upload" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -F "resume=@./candidate.pdf;type=application/pdf" \
  -F "[email protected]" \
  -F "[email protected]" \
  -F "current_ctc=12 LPA" \
  -F "expected_ctc=18 LPA" \
  -F "preferred_location=Bengaluru" \
  -F "years_of_experience=5.5" \
  -F "custom_notes=Candidate prefers a backend platform role"
import requests

with open("candidate.pdf", "rb") as f:
    resp = requests.post(
        f"{BASE_URL}/v2/resumes/upload",
        headers={"Authorization": f"Bearer {api_key}"},
        files={"resume": ("candidate.pdf", f, "application/pdf")},
        data={
            "uploader_email": "[email protected]",
            "referrer_email": "[email protected]",
            "current_ctc": "12 LPA",
            "expected_ctc": "18 LPA",
            "preferred_location": "Bengaluru",
            "years_of_experience": "5.5",
            "custom_notes": "Candidate prefers a backend platform role",
        },
    )
print(resp.json())
{
  "accepted": true,
  "message": "",
  "is_resume": true,
  "refer_id": "AbC123xYz987PqR",
  "alias_email": "[email protected]",
  "uploader_email": "[email protected]",
  "filename": "candidate.pdf",
  "credit_price": 18,
  "credits_added": 18,
  "request_id": "req_..."
}

Shortlists

POST /v2/shortlists
GET /v2/shortlists
DELETE /v2/shortlists/:resumeId
// Add to shortlist
curl -X POST "$BASE_URL/v2/shortlists" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"resume_id": 42, "notes": "Strong Go + search background"}'

// List shortlist
curl -H "Authorization: Bearer $HTC_API_KEY" "$BASE_URL/v2/shortlists"

// Remove from shortlist
curl -X DELETE -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/shortlists/42"

Wallet balance

GET /v2/wallet/balance
curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/wallet/balance"
{ "balance_credits": 500, "request_id": "req_..." }

Claim (purchase) a resume

POST /v2/resumes/:resumeId/claim

Deducts credits and delivers the full CV.

Parameter Type Req Description
recipient_emails string[] No Emails to deliver the full CV to
curl -X POST "$BASE_URL/v2/resumes/42/claim" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipient_emails": ["[email protected]"]
  }'

Owned resumes

GET /v2/owned/resumes?limit=N&offset=N
GET /v2/owned/resumes/:resumeId/detail
// List purchased resumes
curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/owned/resumes?limit=20&offset=0"

// Get full detail of owned resume
curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/owned/resumes/42/detail"

Resume visibility

GET /v2/resumes/:resumeId/visibility
PATCH /v2/resumes/:resumeId/visibility

Control whether a resume is private, portfolio-masked, or fully shared.

curl -X PATCH "$BASE_URL/v2/resumes/42/visibility" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "visibility_mode": "portfolio_masked" }'

Mail aliases, inbox messages, reply, and forward

Mail aliases

GET /v2/mail-aliases
GET /v2/mail-aliases/availability?localpart=team-alpha
POST /v2/mail-aliases
PATCH /v2/mail-aliases/:id
DELETE /v2/mail-aliases/:id
// Create a forwarding alias
curl -X POST "$BASE_URL/v2/mail-aliases" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "localpart": "hiring-ops",
    "forward_to_email": "[email protected]",
    "forwarding_enabled": true
  }'
// List all aliases
curl -H "Authorization: Bearer $HTC_API_KEY" "$BASE_URL/v2/mail-aliases"
{
  "items": [
    { "id": 12, "alias_email": "[email protected]", "is_default": true, "forwarding_enabled": false },
    { "id": 18, "alias_email": "[email protected]", "is_default": false, "forward_to_email": "[email protected]", "forwarding_enabled": true }
  ],
  "alias_domain": "hiddentalent.club",
  "max_aliases": 20
}

Inbox messages

GET /v2/inbox/messages?limit=20&offset=0
GET /v2/inbox/messages/:id
POST /v2/inbox/messages/:id/reply
POST /v2/inbox/messages/:id/forward
// List inbox messages
curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/inbox/messages?limit=20&offset=0"

// Get single message
curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/inbox/messages/501"

// Reply to a message
curl -X POST "$BASE_URL/v2/inbox/messages/501/reply" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "subject": "Re: Resume follow-up",
    "body_text": "Thanks for the note. We will review and get back shortly."
  }'

// Forward a message
curl -X POST "$BASE_URL/v2/inbox/messages/501/forward" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to_email": "[email protected]",
    "note": "Please review this inbound candidate thread."
  }'

API keys, BYOK provider keys, organization members

Merchant API keys

POST /v2/api-keys
GET /v2/api-keys
DELETE /v2/api-keys/:id
// Create a new API key
curl -X POST "$BASE_URL/v2/api-keys" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "ci-worker"}'

// Response (raw key shown ONCE)
{ "id": 5, "name": "ci-worker", "key_prefix": "htc_a3b...", "raw_key": "htc_a3b8d1...", "request_id": "req_..." }

// List all keys
curl -H "Authorization: Bearer $HTC_API_KEY" "$BASE_URL/v2/api-keys"

// Revoke a key
curl -X DELETE -H "Authorization: Bearer $HTC_API_KEY" "$BASE_URL/v2/api-keys/5"

BYOK provider keys

POST /v2/byok/keys
GET /v2/byok/keys
DELETE /v2/byok/keys/:provider

Supported providers: groq, cerebras, openrouter. Used when platform LLM quota is exhausted during reranking.

curl -X POST "$BASE_URL/v2/byok/keys" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "provider": "groq", "api_key": "gsk_live_your_key" }'

Organization members & invites

GET /v2/org/members
GET /v2/org/member-invites
POST /v2/org/member-invites
// List members
curl -H "Authorization: Bearer $HTC_API_KEY" "$BASE_URL/v2/org/members"

// Invite a new member
curl -X POST "$BASE_URL/v2/org/member-invites" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "[email protected]", "role": "member" }'

Fund-level talent pool, visibility controls, and settings

Portfolio endpoints

GET /v2/portfolio/context
POST /v2/portfolio/bootstrap
GET /v2/portfolio/admin/settings
PATCH /v2/portfolio/admin/settings
GET /v2/portfolio/admin/organizations
POST /v2/portfolio/admin/organizations
// Bootstrap a new portfolio
curl -X POST "$BASE_URL/v2/portfolio/bootstrap" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Ventures Portfolio",
    "site_name": "Acme Talent Hub",
    "site_tagline": "Internal talent sharing for Acme portfolio companies"
  }'

// Get portfolio context
curl -H "Authorization: Bearer $HTC_API_KEY" "$BASE_URL/v2/portfolio/context"

// Update portfolio settings
curl -X PATCH "$BASE_URL/v2/portfolio/admin/settings" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "default_visibility_mode": "portfolio_masked",
    "allow_company_self_share": true,
    "site_name": "Acme Talent Hub"
  }'

// Add organization to portfolio
curl -X POST "$BASE_URL/v2/portfolio/admin/organizations" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "org_id": "user_company123" }'

Build a Codex Skill with Hidden Talent Club

OpenAI Codex / Custom GPT Integration

Turn Hidden Talent Club into a Codex-powered recruiting assistant in 3 steps.

  1. Get your API key — create a merchant API key in the Console or via POST /v2/api-keys. Export it as HTC_API_KEY.
  2. Define your tools — use the OpenAPI-style action schema below to let your GPT call HTC endpoints.
  3. Set the system prompt — paste the prompt template below into your Custom GPT or Codex agent configuration.

System prompt template

You are a recruiting assistant powered by Hidden Talent Club.
You have access to a resume marketplace API.
BASE_URL: https://yourdomain.hiddentalent.club
API_KEY: (injected at runtime)

CAPABILITIES:
1. Search resumes: POST /v2/catalog/search with query_text
2. View resume details: GET /v2/catalog/resumes/{id}/detail
3. Find similar candidates: GET /v2/catalog/resumes/{id}/similar
4. Add to shortlist: POST /v2/shortlists with resume_id
5. Check wallet: GET /v2/wallet/balance
6. Purchase resume: POST /v2/resumes/{id}/claim
7. Upload resume: POST /v2/resumes/upload (multipart PDF)
8. Manage inbox: GET/POST /v2/inbox/messages

RULES:
- Always search before purchasing
- Show match scores when displaying results
- Ask for confirmation before purchasing (costs credits)
- Default to semantic search (rerank=false) unless user asks for ranking

Codex action schema

{
  "openapi": "3.1.0",
  "info": { "title": "Hidden Talent Club API", "version": "2.0.0" },
  "servers": [{ "url": "https://yourdomain.hiddentalent.club" }],
  "paths": {
    "/v2/catalog/search": {
      "post": {
        "operationId": "searchResumes",
        "summary": "Search resumes with semantic query",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["query_text"],
                "properties": {
                  "query_text": { "type": "string", "description": "Natural language hiring brief" },
                  "limit": { "type": "integer", "minimum": 1, "maximum": 100, "default": 20 },
                  "rerank": { "type": "boolean", "default": false },
                  "years_experience_min": { "type": "number" },
                  "years_experience_max": { "type": "number" },
                  "current_ctc_inr_lpa_min": { "type": "number" },
                  "current_ctc_inr_lpa_max": { "type": "number" },
                  "preferred_locations": { "type": "array", "items": { "type": "string" } }
                }
              }
            }
          }
        }
      }
    },
    "/v2/catalog/resumes/{resumeId}/detail": {
      "get": {
        "operationId": "getResumeDetail",
        "summary": "Get anonymized resume detail",
        "parameters": [
          { "name": "resumeId", "in": "path", "required": true, "schema": { "type": "integer" } }
        ]
      }
    },
    "/v2/shortlists": {
      "post": {
        "operationId": "addToShortlist",
        "summary": "Add resume to shortlist",
        "requestBody": {
          "content": { "application/json": { "schema": {
            "type": "object",
            "required": ["resume_id"],
            "properties": {
              "resume_id": { "type": "integer" },
              "notes": { "type": "string" }
            }
          }}}
        }
      }
    },
    "/v2/wallet/balance": {
      "get": { "operationId": "getWalletBalance", "summary": "Check credit balance" }
    },
    "/v2/resumes/{resumeId}/claim": {
      "post": {
        "operationId": "claimResume",
        "summary": "Purchase and unlock a resume",
        "parameters": [
          { "name": "resumeId", "in": "path", "required": true, "schema": { "type": "integer" } }
        ],
        "requestBody": {
          "content": { "application/json": { "schema": {
            "type": "object",
            "required": [],
            "properties": {
              "recipient_emails": { "type": "array", "items": { "type": "string" } }
            }
          }}}
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer" }
    }
  },
  "security": [{ "bearerAuth": [] }]
}

Example: full Codex workflow

# Step 1: Search for candidates
curl -X POST "$BASE_URL/v2/catalog/search" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"query_text": "Senior Go engineer, distributed systems", "limit": 5}'

# Step 2: View top result details
curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/catalog/resumes/42/detail"

# Step 3: Shortlist the candidate
curl -X POST "$BASE_URL/v2/shortlists" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"resume_id": 42, "notes": "Strong distributed systems background"}'

# Step 4: Check wallet balance
curl -H "Authorization: Bearer $HTC_API_KEY" "$BASE_URL/v2/wallet/balance"

# Step 5: Purchase the resume
curl -X POST "$BASE_URL/v2/resumes/42/claim" \
  -H "Authorization: Bearer $HTC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"recipient_emails": ["[email protected]"]}'

# Step 6: View the full, owned resume
curl -H "Authorization: Bearer $HTC_API_KEY" \
  "$BASE_URL/v2/owned/resumes/42/detail"

Build a Claude Skill with Hidden Talent Club

Anthropic Claude / Claude Desktop Integration

Connect Claude to the Hidden Talent Club MCP server or use HTTP-based tool definitions.

Option A: MCP Connection (Claude Desktop)

Hidden Talent Club exposes a full MCP server. Add this to your claude_desktop_config.json:

{
  "mcpServers": {
    "hiddentalentclub": {
      "url": "https://yourdomain.hiddentalent.club/mcp",
      "headers": {
        "Authorization": "Bearer htc_your_api_key_here"
      }
    }
  }
}

Available MCP tools: resumes_search_v2, resume_detail_get, resumes_similar, resume_claim, owned_resumes_list, owned_resume_detail_get, resume_metrics_get, shortlist_add, shortlist_list, shortlist_remove, recruiter_resumes_list, resume_tags_set.

Option B: HTTP Tool Definitions

For Claude API or custom integrations, define tools as HTTP calls:

{
  "tools": [
    {
      "name": "search_resumes",
      "description": "Search the Hidden Talent Club resume catalog using a natural-language query. Returns anonymized candidate matches with scores.",
      "input_schema": {
        "type": "object",
        "required": ["query_text"],
        "properties": {
          "query_text": { "type": "string", "description": "Natural language hiring brief" },
          "limit": { "type": "integer", "description": "Max results (1-100)", "default": 20 },
          "rerank": { "type": "boolean", "description": "Enable LLM reranking", "default": false },
          "years_experience_min": { "type": "number" },
          "years_experience_max": { "type": "number" },
          "preferred_locations": { "type": "array", "items": { "type": "string" } }
        }
      }
    },
    {
      "name": "get_resume_detail",
      "description": "Get the full anonymized detail of a specific resume by ID.",
      "input_schema": {
        "type": "object",
        "required": ["resume_id"],
        "properties": {
          "resume_id": { "type": "integer", "description": "The resume ID to look up" }
        }
      }
    },
    {
      "name": "shortlist_resume",
      "description": "Add a resume to the recruiter's shortlist for tracking.",
      "input_schema": {
        "type": "object",
        "required": ["resume_id"],
        "properties": {
          "resume_id": { "type": "integer" },
          "notes": { "type": "string", "description": "Why this candidate was shortlisted" }
        }
      }
    },
    {
      "name": "claim_resume",
      "description": "Purchase a resume to unlock the full CV. Costs credits.",
      "input_schema": {
        "type": "object",
        "required": ["resume_id"],
        "properties": {
          "resume_id": { "type": "integer" },
          "recipient_emails": { "type": "array", "items": { "type": "string" } }
        }
      }
    },
    {
      "name": "check_balance",
      "description": "Check the current wallet credit balance.",
      "input_schema": { "type": "object", "properties": {} }
    }
  ]
}

Claude system prompt

You are a recruiting assistant connected to the Hidden Talent Club API.
You help recruiters find, evaluate, shortlist, and purchase candidate resumes.

When the user describes a hiring need:
1. Use search_resumes with a clear query_text
2. Present results with title, experience, location, CTC, and match score
3. Offer to view details, shortlist, or purchase candidates

When purchasing:
- Always check balance first
- Always ask for explicit confirmation

Endpoint base: https://yourdomain.hiddentalent.club
Auth: Bearer token (injected)

Example: Claude Python agent implementation

import anthropic, requests

client = anthropic.Anthropic()
BASE_URL = "https://yourdomain.hiddentalent.club"
API_KEY = "htc_your_key"

def execute_tool(name, input):
    headers = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
    if name == "search_resumes":
        r = requests.post(f"{BASE_URL}/v2/catalog/search", headers=headers, json=input)
    elif name == "get_resume_detail":
        r = requests.get(f"{BASE_URL}/v2/catalog/resumes/{input['resume_id']}/detail", headers=headers)
    elif name == "shortlist_resume":
        r = requests.post(f"{BASE_URL}/v2/shortlists", headers=headers, json=input)
    elif name == "claim_resume":
        r = requests.post(f"{BASE_URL}/v2/resumes/{input['resume_id']}/claim", headers=headers, json=input)
    elif name == "check_balance":
        r = requests.get(f"{BASE_URL}/v2/wallet/balance", headers=headers)
    return r.json()

# Example conversation
response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=4096,
    system="You are a recruiting assistant connected to Hidden Talent Club...",
    tools=[...],  # tool definitions from above
    messages=[{"role": "user", "content": "Find me 5 senior Go engineers in Bengaluru"}]
)

# Process tool calls
for block in response.content:
    if block.type == "tool_use":
        result = execute_tool(block.name, block.input)
        print(f"Tool {block.name}: {result}")

Example: end-to-end Claude hiring workflow

# 1. User: "Find senior ML engineers with 5-10 years experience"
#    → Claude calls search_resumes(query_text="senior ML engineer", years_experience_min=5, years_experience_max=10)
#    → Returns 10 candidates with match scores

# 2. User: "Tell me more about candidate 42"
#    → Claude calls get_resume_detail(resume_id=42)
#    → Shows anonymized profile, skills, experience summary

# 3. User: "Shortlist candidates 42 and 57"
#    → Claude calls shortlist_resume(resume_id=42, notes="Strong ML background")
#    → Claude calls shortlist_resume(resume_id=57, notes="Good platform experience")

# 4. User: "Purchase resume 42"
#    → Claude calls check_balance() → Returns { balance_credits: 500 }
#    → Claude asks: "This will cost 100 credits. You have 500. Confirm?"
#    → User: "Yes"
#    → Claude calls claim_resume(resume_id=42)
#    → Full CV delivered to recruiter's email

Error codes and conventions

Error response format

{ "error": "error_code", "message": "Human-readable description", "request_id": "req_..." }
Code HTTP Description
invalid_request 400 Missing or malformed parameter
unauthorized 401 Missing or invalid API key
resume_hidden 403 Resume not visible to your organization
resume_not_found 404 Resume does not exist
insufficient_credits 402 Wallet balance too low for purchase
pricing_quote_failed 502 Pricing service unavailable

Every response includes a request_id field for debugging and support.