REST API
v1 · Base URL: https://unitityai.com/api/v1
All API requests require a Bearer token in the Authorization header. Generate tokens in your workspace Settings → API Tokens.
# All requests must include: Authorization: Bearer uai_your_token_here Content-Type: application/json
candidates:read— List and read candidate profilescandidates:write— Create and update candidatesrequisitions:read— List open requisitionspipeline:read— Read stage counts and stuck alertspipeline:write— Advance candidate stages*— Full access (admin only)/api/v1/candidatesList all candidates in your pipeline.
Parameters
| stage | string | optional | Filter by stage: applied, ai_screened, interview_scheduled, interviewed, offer_sent, offer_accepted, onboarding, placed |
| req_id | string | optional | Filter by requisition UUID |
| limit | integer | optional | Max results (default 50, max 200) |
| offset | integer | optional | Pagination offset |
Example Response
{
"data": [
{
"id": "a1b2c3...",
"name": "Jordan Rivera",
"email": "j.rivera@email.com",
"phone": "720-555-0101",
"stage": "interview_scheduled",
"resume_url": "https://...",
"req_title": "Sr. Solar Sales Engineer",
"req_id": "d4e5f6...",
"created_at": "2026-07-02T08:44:00Z",
"updated_at": "2026-07-06T09:14:00Z"
}
],
"count": 1,
"offset": 0,
"limit": 50
}/api/v1/candidatesCreate a new candidate in your pipeline. Useful for syncing from your ATS or CRM.
Parameters
| name | string | required | Full name |
| string | optional | Email address | |
| phone | string | optional | Phone number |
| req_id | string | optional | Requisition UUID to assign candidate to |
| stage | string | optional | Initial stage (default: applied) |
Example Response
{
"data": {
"id": "a1b2c3...",
"name": "Alex Johnson",
"email": "alex@example.com",
"stage": "applied",
"created_at": "2026-07-07T20:00:00Z"
}
}/api/v1/requisitionsList requisitions with candidate counts.
Parameters
| status | string | optional | open (default), on_hold, filled, draft, closed |
| limit | integer | optional | Max results (default 50, max 200) |
Example Response
{
"data": [
{
"id": "req_uuid",
"title": "Sr. Solar Sales Engineer",
"department": "Sales",
"location": "Castle Rock, CO",
"job_type": "direct_hire",
"status": "open",
"candidate_count": "12",
"offers_pending": "1",
"created_at": "2026-07-01T00:00:00Z"
}
],
"count": 1
}/api/v1/pipelineGet pipeline stage distribution and stuck candidate alerts.
Example Response
{
"data": {
"stage_counts": {
"applied": 8,
"ai_screened": 5,
"interview_scheduled": 3,
"interviewed": 2,
"offer_sent": 1
},
"total_active": 19,
"stuck_candidates": [
{
"id": "cand_uuid",
"name": "Marcus Webb",
"stage": "ai_screened",
"days_in_stage": 8,
"req_title": "Sr. Solar Sales Engineer"
}
]
}
}/api/v1/pipelineAdvance or change a candidate's pipeline stage.
Parameters
| candidate_id | string | required | Candidate UUID |
| stage | string | required | Target stage: applied, ai_screened, interview_scheduled, interviewed, offer_sent, offer_accepted, onboarding, placed, rejected |
Example Response
{
"data": {
"id": "cand_uuid",
"name": "Marcus Webb",
"stage": "interview_scheduled",
"updated_at": "2026-07-07T20:30:00Z"
}
}Subscribe to real-time events from Unitity AI. When a subscribed event occurs, we send an HTTP POST request with a JSON payload to your configured endpoint URL. Manage webhooks in your workspace Settings → Webhooks.
candidate.createdA new candidate was added to the pipelinecandidate.stage_changedA candidate's pipeline stage was updatedoffer.sentAn offer letter was sent to a candidateoffer.acceptedA candidate accepted their offerplacement.createdA new placement record was createdEvery webhook delivery is a JSON POST with this envelope:
{
"event": "candidate.stage_changed",
"data": {
"candidateId": "a1b2c3...",
"name": "Jordan Rivera",
"oldStage": "interview_scheduled",
"newStage": "interviewed",
"reqId": "d4e5f6..."
},
"timestamp": "2026-07-08T21:00:00.000Z",
"tenantSlug": "acme-staffing"
}Content-Type: application/json X-Unitity-Event: candidate.stage_changed X-Unitity-Signature: <hmac-sha256-hex-digest>
Each webhook is signed with HMAC-SHA256 using the endpoint's unique secret (shown once at creation time). Compute the signature over the raw request body and compare it to the X-Unitity-Signature header:
const crypto = require("crypto");
function verifySignature(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signatureHeader)
);
}/api/webhooksList webhook endpoints for your tenant (requires session auth).
Example Response
{
"data": [
{
"id": "wh_uuid",
"url": "https://your-service.com/webhooks/unitity",
"events": ["candidate.created", "offer.accepted"],
"active": true,
"description": "Sync to internal CRM",
"last_triggered_at": "2026-07-08T20:00:00Z",
"failure_count": 0,
"created_at": "2026-07-01T00:00:00Z"
}
]
}/api/webhooksCreate a new webhook endpoint. The signing secret is returned only once.
Parameters
| url | string | required | Must be an https:// URL |
| events | string[] | optional | Event types to subscribe to |
| description | string | optional | Human-readable label |
Example Response
{
"success": true,
"webhook": {
"id": "wh_uuid",
"url": "https://your-service.com/webhooks/unitity",
"secret": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b85",
"events": ["candidate.created", "candidate.stage_changed", "offer.accepted"],
"active": true,
"created_at": "2026-07-08T21:00:00Z"
}
}/api/webhooks/{id}Get webhook details plus the last 10 delivery attempts.
Example Response
{
"webhook": { "id": "wh_uuid", "url": "...", "events": ["..."], "active": true },
"deliveries": [
{ "id": "d_uuid", "event_type": "candidate.created", "response_status": 200, "success": true, "duration_ms": 184, "created_at": "2026-07-08T20:00:00Z" }
]
}/api/webhooks/{id}Update url, events, active state, or description.
Parameters
| url | string | optional | New https:// endpoint URL |
| events | string[] | optional | Replace subscribed events |
| active | boolean | optional | Enable or disable delivery |
| description | string | optional | Update label |
Example Response
{ "success": true, "webhook": { "id": "wh_uuid", "active": false } }/api/webhooks/{id}Deactivate a webhook (soft delete — sets active=false).
Example Response
{ "success": true }/api/webhooks/{id}/testSend a webhook.test event to the endpoint and record the delivery result.
Example Response
{ "success": true, "status": 200, "durationMs": 142, "responseBody": "ok" }401UnauthorizedMissing or invalid API token403ForbiddenValid token but missing required scope404Not FoundResource does not exist in your tenant400Bad RequestMissing or invalid request parameters500Server ErrorInternal error — contact support# All errors return:
{
"error": "Human-readable error message"
}# 1. Get your pipeline overview
curl https://unitityai.com/api/v1/pipeline \
-H "Authorization: Bearer uai_your_token"
# 2. List candidates in interview stage
curl "https://unitityai.com/api/v1/candidates?stage=interview_scheduled" \
-H "Authorization: Bearer uai_your_token"
# 3. Push a candidate from your CRM
curl -X POST https://unitityai.com/api/v1/candidates \
-H "Authorization: Bearer uai_your_token" \
-H "Content-Type: application/json" \
-d '{"name":"Alex Johnson","email":"alex@co.com","stage":"applied"}'
# 4. Advance a candidate's stage
curl -X POST https://unitityai.com/api/v1/pipeline \
-H "Authorization: Bearer uai_your_token" \
-H "Content-Type: application/json" \
-d '{"candidate_id":"uuid-here","stage":"interviewed"}'Unitity AI API v1 · Manage your tokens