API Reference

Kyndle Hire API

A REST API and signed webhooks to integrate Kyndle Hire with your own tools. All responses are JSON, and every request is scoped to the company that owns the API key.

Base URL

https://app.kyndlehire.com/api/v1

Create keys and webhooks in your workspace under Settings → Developers & API. API access is available on the Growth plan and up, and is rate-limited to 120 requests per minute per key.

Authentication

Authenticate with a bearer token — your API key — in the Authorization header. Keys are shown once at creation; store them securely and never expose them in client-side code.

curl https://app.kyndlehire.com/api/v1/jobs \
  -H "Authorization: Bearer kh_live_xxxxxxxxxxxx"

Keys have scopes: read (all GET endpoints) and write (create/update). A read-only key hitting a write endpoint gets 403.

Errors

Errors return a JSON body with an error message and a standard status code.

StatusMeaning
401Missing or invalid API key
403Key lacks the required scope
400Invalid request body
404Resource not found
429Rate limit exceeded (120 requests / minute per key)

Jobs

GET/jobs

List jobs. Query params: limit (max 100), status.

curl "https://app.kyndlehire.com/api/v1/jobs?status=open&limit=20" \
  -H "Authorization: Bearer kh_live_xxx"

{
  "data": [
    {
      "id": "…", "title": "Backend Engineer", "slug": "backend-engineer",
      "status": "open", "employment_type": "full_time",
      "location_city": "Dubai", "is_remote": false,
      "published": true, "published_at": "2026-08-01T…", "created_at": "…"
    }
  ]
}
POST/jobs

Create a job (requires write). Only title is required; the rest fall back to sensible defaults. Fires a job.created webhook.

curl -X POST https://app.kyndlehire.com/api/v1/jobs \
  -H "Authorization: Bearer kh_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Senior Frontend Engineer",
    "description": "Build our candidate experience.",
    "employment_type": "full_time",
    "work_mode": "remote",
    "location_city": "Dubai",
    "is_remote": true
  }'

// 201 Created → { "data": { "id": "…", "slug": "…", … } }

Candidates

GET/candidates

List candidates. Query param: limit (max 100).

curl https://app.kyndlehire.com/api/v1/candidates \
  -H "Authorization: Bearer kh_live_xxx"

{
  "data": [
    { "id": "…", "full_name": "Ada Lovelace", "email": "ada@example.com",
      "headline": "Backend Engineer", "status": "active", "source": "career_site",
      "created_at": "…" }
  ]
}
POST/candidates

Create a candidate (requires write). full_name and email are required. Fires a candidate.created webhook.

curl -X POST https://app.kyndlehire.com/api/v1/candidates \
  -H "Authorization: Bearer kh_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "full_name": "Ada Lovelace", "email": "ada@example.com",
        "headline": "Backend Engineer", "location_city": "London" }'

// 201 Created → { "data": { "id": "…", … } }

Applications

GET/applications

List applications. Query params: limit, job_id.

curl "https://app.kyndlehire.com/api/v1/applications?job_id=…" \
  -H "Authorization: Bearer kh_live_xxx"

{
  "data": [
    { "id": "…", "job_id": "…", "candidate_id": "…",
      "status": "new", "stage_id": "…", "source": "career_site", "created_at": "…" }
  ]
}
POST/applications

Attach a candidate to a job (requires write). job_id and candidate_id must belong to your company. Fires application.created.

curl -X POST https://app.kyndlehire.com/api/v1/applications \
  -H "Authorization: Bearer kh_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "job_id": "…", "candidate_id": "…", "cover_letter": "Excited to apply!" }'

// 201 Created → { "data": { "id": "…", "status": "new", … } }
POST/applications/inbound

One-shot inbound application from an external board (Naukri, Indeed Apply, …). Creates or matches the candidate by email, pulls their résumé from resume_url into the private bucket, creates the application, and fires application.created — so it lands in the Applicants dashboard with a downloadable CV.

curl -X POST https://app.kyndlehire.com/api/v1/applications/inbound \
  -H "Authorization: Bearer kh_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "job_slug": "backend-engineer",
    "full_name": "Priya Nair", "email": "priya@example.com",
    "phone": "+971 55 000 1111",
    "resume_url": "https://boards.example.com/cv/priya.pdf",
    "source": "naukrigulf"
  }'

// 201 Created → { "data": { "candidate_id": "…", "job_id": "…", "status": "new" } }

Webhooks

Register an HTTPS endpoint and pick events. When an event fires, Kyndle Hire sends a POST with a JSON body and these headers:

  • X-Kyndle-Event — the event name
  • X-Kyndle-Signaturesha256=<hmac> of the raw body

Events

application.createdcandidate.createdjob.createdjob.published

Payload

{
  "event": "application.created",
  "created_at": "2026-08-15T16:55:35.033Z",
  "data": {
    "job": { "id": "…", "title": "Backend Engineer" },
    "candidate": { "id": "…", "full_name": "Ada Lovelace", "email": "ada@example.com" },
    "source": "career_site"
  }
}

Verifying the signature

Recompute the HMAC over the rawrequest body with your endpoint's signing secret and compare in constant time.

import crypto from "node:crypto";

function verify(rawBody, header, secret) {
  const expected =
    "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}

Delivery status (last response, failures) is shown next to each endpoint in Settings → Developers & API.

Ready to build?

Create your first API key and webhook in your workspace settings.

Get started