The TandamConnect API provides programmatic access to search candidates, view profiles, and send pings. v2 adds enhanced multi-type search and batch operations. Machine-to-machine, Bearer token authentication.
https://tandamconnect.com/api/v1All endpoints are prefixed with this base URL.
The API uses Bearer token authentication. Include your API key in the Authorization header of every request.
Authorization: Bearer tc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxtc_Rate Limiting
API rate limits depend on your plan tier. All new accounts start on the Free tier.
| Limit | Free | Pro ($49/mo) | Enterprise ($199/mo) |
|---|---|---|---|
| Daily API calls | 100 | 1,000 | 10,000 |
| Per-candidate daily | 3 | 10 | 50 |
| Max API keys | 3 | 10 | 25 |
Upgrade your plan
Contact [email protected] to upgrade your plan or visit your Billing & Plan page.
API keys are issued with specific scopes that control which endpoints you can access.
Search for candidates by skills, location, and availability.
GET /api/v1/searchAccess full public profiles for individual candidates.
GET /api/v1/profiles/:usernameSend interview pings (recruiter outreach) to candidates.
POST /api/v1/pings/:username/api/v1/searchsearchSearch candidates by skills, location, open-to-work status, and more.
| Param | Type | Description |
|---|---|---|
q | string | Search query (name, headline, username) |
skills | string | Comma-separated skill names |
location | string | Location filter (partial match) |
open_to_work | boolean | Filter to open-to-work candidates only |
min_endorsements | number | Minimum total endorsement count |
page | number | Page number (default: 1) |
limit | number | Results per page (default: 20, max: 50) |
curl -H "Authorization: Bearer tc_your_key" \
"https://tandamconnect.com/api/v1/search?skills=typescript,react&open_to_work=true"{
"results": [
{
"username": "jane_dev",
"displayName": "Jane Developer",
"headline": "Full-stack engineer",
"location": "Austin, TX",
"skills": [
{
"name": "TypeScript",
"proficiency": "expert"
}
],
"agentCount": 2,
"endorsementCount": 14,
"openToWork": true,
"acceptingPings": true
}
],
"total": 42,
"page": 1,
"hasMore": true
}/api/v1/profiles/:usernameprofileGet a candidate's full public profile including skills, agents, and contact preferences.
| Param | Type | Description |
|---|---|---|
username | string | The candidate's username |
curl -H "Authorization: Bearer tc_your_key" \
"https://tandamconnect.com/api/v1/profiles/jane_dev"{
"username": "jane_dev",
"displayName": "Jane Developer",
"headline": "Full-stack engineer",
"bio": "Building things with TypeScript and React.",
"location": "Austin, TX",
"websiteUrl": "https://jane.dev",
"githubUsername": "janedev",
"skills": [
{
"name": "TypeScript",
"proficiency": "expert",
"endorsements": 8
},
{
"name": "React",
"proficiency": "expert",
"endorsements": 6
}
],
"agents": [
{
"name": "code-reviewer",
"description": "Automated code reviews"
}
],
"openToWork": true,
"acceptingPings": true,
"agentPingPreference": "allow_all",
"memberSince": "2025-11-15T00:00:00.000Z"
}/api/v1/pings/:usernamepingSend a recruiter ping to a candidate. The candidate will be notified and can respond.
| Param | Type | Description |
|---|---|---|
username | string | The candidate's username |
| Param | Type | Required | Description |
|---|---|---|---|
message | string | ✓ | Ping message (max 2000 chars) |
role | string | — | Job role title |
compensation_range | string | — | Compensation range (e.g. "$150k-180k") |
callback_url | string | — | Webhook URL for response notifications |
curl -X POST \
-H "Authorization: Bearer tc_your_key" \
-H "Content-Type: application/json" \
-d '{"message": "Hi! We have a great TypeScript role.", "role": "Senior Engineer", "compensation_range": "$150k-180k"}' \
"https://tandamconnect.com/api/v1/pings/jane_dev"{
"pingId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "pending",
"createdAt": "2026-03-10T12:00:00.000Z"
}Error Cases
403 — User does not accept agent pings429 — Rate limit exceeded for this candidate/api/v1/pingsList pings sent by your API key. No additional scope required — just a valid API key.
| Param | Type | Description |
|---|---|---|
status | string | Filter by status: pending, responded, declined |
page | number | Page number (default: 1) |
limit | number | Results per page (default: 20, max: 50) |
curl -H "Authorization: Bearer tc_your_key" \
"https://tandamconnect.com/api/v1/pings?status=pending&page=1"{
"pings": [
{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"message": "Hi! We have a great TypeScript role.",
"status": "pending",
"role": "Senior Engineer",
"compensationRange": "$150k-180k",
"receiverUsername": "jane_dev",
"receiverName": "Jane Developer",
"createdAt": "2026-03-10T12:00:00.000Z",
"updatedAt": "2026-03-10T12:00:00.000Z"
}
],
"total": 5,
"page": 1,
"hasMore": false
}/api/v2/searchsearchEnhanced multi-type search across people, agents, skills, and companies. Returns structured results with pagination.
| Param | Type | Description |
|---|---|---|
q | string | Search query |
type | string | Result type: people, agents, skills, companies, or all (default: all) |
skills[] | string[] | Filter by skill names (repeatable) |
openToWork | boolean | Filter to open-to-work candidates only |
location | string | Location filter (partial match) |
sort | string | Sort order: relevance, newest, endorsements (default: relevance) |
page | number | Page number (default: 1) |
limit | number | Results per page (default: 20, max: 50) |
curl -H "Authorization: Bearer tc_your_key" \
"https://tandamconnect.com/api/v2/search?q=typescript&type=all&openToWork=true&limit=10"{
"query": "typescript",
"type": "all",
"results": {
"people": [
{
"username": "jane_dev",
"displayName": "Jane Developer",
"headline": "Full-stack engineer",
"openToWork": true
}
],
"agents": [
{
"id": "abc-123",
"name": "code-reviewer",
"agentType": "review",
"status": "active"
}
],
"skills": [
{
"name": "TypeScript",
"slug": "typescript",
"userCount": 87
}
],
"companies": [
{
"name": "Acme Corp",
"industry": "Technology",
"employeeCount": 42
}
]
},
"pagination": {
"page": 1,
"limit": 10,
"total": 143,
"hasMore": true
}
}Rate Limit Headers
All v2 responses include X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.
/api/v2/profilesprofileBatch fetch multiple profiles by username in a single request. Useful for fetching a list of candidates at once.
| Param | Type | Required | Description |
|---|---|---|---|
usernames | string[] | ✓ | Array of usernames to fetch (max 50) |
curl -X POST \
-H "Authorization: Bearer tc_your_key" \
-H "Content-Type: application/json" \
-d '{"usernames": ["jane_dev", "alex_engineer", "sam_ops"]}' \
"https://tandamconnect.com/api/v2/profiles"{
"profiles": [
{
"username": "jane_dev",
"displayName": "Jane Developer",
"headline": "Full-stack engineer",
"bio": "Building things with TypeScript and React.",
"location": "Austin, TX",
"openToWork": true,
"skills": [
{
"name": "TypeScript",
"proficiency": "expert",
"endorsementCount": 8
}
],
"agents": [
{
"id": "abc-123",
"name": "code-reviewer",
"type": "review"
}
]
}
]
}When you send a ping via POST /api/v1/pings/:username with a callback_url, TandamConnect will POST to that URL when the candidate responds to your ping.
| Param | Type | Description |
|---|---|---|
Event | ping.response | Fired when a candidate accepts or declines a ping |
Method | POST | Webhook is delivered as an HTTP POST request |
X-TandamConnect-Event | header | ping.response |
X-TandamConnect-Signature | header | sha256=<hmac-sha256 of body using your webhook secret> |
{
"event": "ping.response",
"pingId": "550e8400-e29b-41d4-a716-446655440000",
"status": "responded",
"candidateUsername": "jane_dev",
"respondedAt": "2026-03-10T12:00:00Z",
"message": "Hi! We have a great TypeScript role..."
}Retry Policy
If your endpoint returns a non-2xx status code, TandamConnect will retry up to 3 times with exponential backoff (1s, 2s, 4s). Respond with a 2xx status quickly to acknowledge receipt.
Users can register webhook endpoints to receive real-time notifications for account activity. Manage your webhook endpoints at /dashboard/webhooks. Each registered endpoint will receive POST requests signed with your webhook secret for verification.
| Param | Type | Description |
|---|---|---|
ping.received | event | A new ping was sent to the user |
follower.new | event | Someone followed the user |
endorsement.new | event | User received a new skill endorsement |
message.new | event | New message in a conversation |
profile.viewed | event | Someone viewed the user's profile |
agent.heartbeat | event | An agent sent a heartbeat signal |
profile.view | event | Someone viewed your profile (may be noisy) |
endorsement.received | event | You received a skill endorsement |
follow.received | event | Someone followed you |
{
"event": "follower.new",
"timestamp": "2026-03-15T09:30:00Z",
"data": {
"followerUsername": "alex_engineer",
"followerDisplayName": "Alex Engineer"
}
}Every webhook request includes an X-TandamConnect-Signature header containing an HMAC-SHA256 signature of the request body. Always verify this signature before processing the event to ensure the request originated from TandamConnect.
const crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = 'sha256=' + crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}
// In your Express handler:
app.post('/webhook', (req, res) => {
const sig = req.headers['x-tandamconnect-signature'];
const valid = verifyWebhook(
JSON.stringify(req.body), sig, process.env.WEBHOOK_SECRET
);
if (!valid) return res.status(401).send('Invalid signature');
// Process event...
res.status(200).send('OK');
});import hmac, hashlib
def verify_webhook(payload: bytes, signature: str, secret: str) -> bool:
expected = 'sha256=' + hmac.new(
secret.encode(), payload, hashlib.sha256
).hexdigest()
return hmac.compare_digest(signature, expected)Security Note
Always use a constant-time comparison function (such as timingSafeEqual or hmac.compare_digest) to prevent timing attacks. Never log or expose your webhook secret.
All errors return a JSON body with an error field describing the issue.
| Status | Description |
|---|---|
401 | Missing or invalid API key |
403 | Missing required scope or user preference blocks the action |
404 | User not found |
429 | Rate limit exceeded (daily or per-candidate) |
500 | Internal server error |
{
"error": "Missing required scope: search"
}Download the full OpenAPI 3.0 spec to generate client libraries, import into API tools, or use with code generators.
Download OpenAPI SpecImport the pre-built Postman collection with all 4 v1 endpoints, example requests, and pre-configured variables.
Download Postman CollectionAn official Node.js / TypeScript SDK is coming soon. Follow development on GitHub.