Contents

v1 · Beta

Partner API

Candidate Intelligence API Integration

Give recruiters more confidence before interviews

Run Candidate Intelligence reports directly inside your ATS to verify candidate information, surface unexpected signals, and generate interview questions in seconds.

Request API Access

Best fit for

Applicant Tracking Systems (ATS)

Recruitment CRMs

Job Boards

Internal Talent Platforms

Executive Search Firms

HR Tech Vendors

Partner Benefits

Why Integrate Candidate Intelligence?

Give your customers additional context before interviews while creating new value inside your platform.

📈

Increase Recruiter Engagement

Keep recruiters inside your ATS by providing candidate verification, interview preparation, and additional hiring insights directly within candidate profiles.

💰

Create a New Revenue Stream

Offer Candidate Intelligence reports to your customers and earn recurring revenue through the partner program.

Differentiate Your Platform

Stand out from competing ATS and recruitment solutions with built-in Candidate Intelligence capabilities.

🔍

No Additional Research Required

Help recruiters uncover relevant information beyond the CV without leaving their workflow.

🎯

Improve Hiring Quality

Help recruiters and hiring managers make more informed decisions by providing additional context beyond the CV, highlighting verified findings, surfacing potential risks, and identifying areas that require further validation.

Fast Integration

Typical implementation requires only a few API endpoints and can be completed in less than a day.

Integration flow

1

Get approved and receive an API key

Request access from TieTalent. Once approved, you receive an API key for your integration.

2

Add a button inside candidate profiles

Add a "Run intelligence" button within candidate profiles. When clicked, it changes to "Running..." while the report generates. Once ready, the report opens automatically and the button becomes "✕ Close report". When closed, the button reverts to "View Intelligence report" to reopen a report you have already generated.

3

Call the TieTalent API when clicked

POST to /api/v1/analyses with the candidate, client (recruiter), and language data. Use your own external IDs on client.id and candidate.id.

4

TieTalent generates the report

The analysis runs in the background. Use GET /api/v1/analyses/{id} both to poll while status is queued or processing (wait at least 10 seconds between requests; see Retry-After) and to retrieve the completed report when status is completed. Call DELETE on the same path to cancel if the recruiter leaves the profile.

5

Optional: precompute on shortlist

When a candidate is shortlisted (or moves to a late pipeline stage), POST with mode: "precompute" so generation can finish before the recruiter clicks. Store the returned id and GET it when opening, or still POST live on click. Live always creates a new id but reuses valid cache content quickly. Do not trigger precompute on first profile open. See Precompute analyses.

6

Display the report in the candidate profile

Render the report JSON in your own UI (see Report types & fields), or open the full hosted report via the signed link in metadata.pdf_download_url: the hosted view also offers the PDF export.

Performance & Latency

Candidate Intelligence is designed to provide a responsive experience directly within recruiter workflows.

Action

Typical Response Time

Existing report found (live cache copy or precompute reuse)

< 1 second

Open a precomputed report (after precompute completed)

Instant (GET completed report)

New report generation

30–60 seconds

Report reuse logic

Reports are uniquely identified by platform + company + candidate.

Cache is scoped per recruiter: your API key identifies the partner integration, and client.id identifies the recruiter (user) within your platform. Different client.id values do not share cache, even under the same API key.

Same client + same candidate fingerprint → cached report content reused instantly (live: new analysis id with metadata.cached; precompute: same analysis id)
Different client company + same candidate → new report generated and billed separately
Same client company + different candidate → new report generated and billed

Cache key fields

candidate.idYour external candidate ID
candidate.first_name + candidate.last_nameCandidate name (normalized)
candidate.companyCurrent company (normalized)
candidate.locationLocation (normalized)
candidate.roleRole or job title (normalized)
report_typeResolved report type (your partner default, or the per-call report_type override). A different report_type than a prior cached run is always a cache miss: a fresh report of the requested type is generated.

Not part of the cache key

candidate.cvOptional CV text: used only on fresh runs. Changing the CV alone does not bust cache.
languageRequested report language. Use force_refresh: true when you need a report in a different language.

Cached reports are reused for up to 6 months. Completed analyses older than that are not returned from cache.

Force refresh

Set force_refresh: true on POST /api/v1/analyses to skip the cache lookup and run the full analysis pipeline: enrichment, live signals, and LLM report generation.

Omit force_refresh or set it to false to allow cache reuse (default).

When to set force_refresh: true

The recruiter explicitly requests updated or refreshed intelligence

Only the CV text changed while profile fields stayed the same

You need a report in a different language than a prior cached run

You want live signals and enrichment re-run regardless of cache

Fresh analysis request

{
  "language": "en",
  "client": {
    "id": "client_company_123",
    "first_name": "Jane",
    "last_name": "Smith",
    "company": "Acme Recruiting"
  },
  "candidate": {
    "id": "candidate_456",
    "first_name": "John",
    "last_name": "Doe",
    "company": "Example Company",
    "location": "London, UK",
    "role": "Software Engineer"
  },
  "force_refresh": true
}

Authentication

Approval required: API keys are issued only to approved partner platforms. Include your key on every request; never expose it in client-side code or public repositories.

HTTP headers

X-API-Key: ats_your_api_key_here
Content-Type: application/json

Create analysis

Optional body fields: candidate.cv (plain-text CV, used only on fresh runs), force_refresh (boolean, default false (see Force refresh), report_type ("hr" or "agency", overrides your partner default for this call only) see Report types & fields), and mode: "precompute" (see Precompute analyses; use candidates instead of candidate for batch).

POST/api/v1/analyses
{
  "language": "en",
  "client": {
    "id": "client_company_123",
    "first_name": "Jane",
    "last_name": "Smith",
    "company": "Acme Recruiting"
  },
  "candidate": {
    "id": "candidate_456",
    "first_name": "John",
    "last_name": "Doe",
    "company": "Example Company",
    "location": "London, UK",
    "role": "Software Engineer",
    "cv": "Optional plain-text CV content…"
  },
  "force_refresh": false
}

force_refresh (optional, default false) skips report reuse and always generates a fresh report. The new report is billed. Omit it unless the recruiter explicitly requests a refresh.

202 Accepted

The Location header points to GET /api/v1/analyses/{id}. Retry-After: 10 indicates when to poll next.

202 Accepted
{
  "id": "cmqp23kgg00067gk0rh6jol5o",
  "status": "queued",
  "candidate_id": "candidate_456",
  "created_at": "2026-06-29T12:00:00.000Z"
}

Precompute analyses

Precompute generates a Candidate Intelligence report ahead of time (for example when a candidate is shortlisted) so the recruiter is less likely to wait 30–60s. Store the returned analysis id and GET it when they open the report, or POST a normal live create on click. Live still returns a new id every time, but reuses valid cache content in under a second.

Use the same POST /api/v1/analyses endpoint with mode: "precompute". There is no separate precompute URL. Poll and retrieve with the same GET /api/v1/analyses/{id} as live runs.

Recommended triggers

Candidate shortlisted

Pipeline stage change into a late / interview-ready stage

Do not trigger on

  • First profile open: avoided for privacy/GDPR and cost reasons after product review

Behavior

  • Returns 202 Accepted with an analysis id immediately: no long-held connection and no streamed preliminary signals on create.
  • Idempotent: if the same partner + client (recruiter) + candidate fingerprint already has an in-flight run or a valid cached report (same 6-month reuse rules as live), the existing analysis id is returned and no new generation starts.
  • Live (non-precompute) POSTs still create a new analysis id every time; cache reuse for live runs copies the report onto that new id (unchanged).
  • Optional force_refresh: true skips completed-cache reuse for precompute (same semantics as live). An in-flight run for the same fingerprint is still returned instead of starting a duplicate.

Single-candidate precompute

Send mode: "precompute" with the same client and candidate objects as a live create. Response shape matches the live 202 Accepted body.

POST/api/v1/analyses
{
  "mode": "precompute",
  "language": "en",
  "client": {
    "id": "client_company_123",
    "first_name": "Jane",
    "last_name": "Smith",
    "company": "Acme Recruiting"
  },
  "candidate": {
    "id": "candidate_456",
    "first_name": "John",
    "last_name": "Doe",
    "company": "Example Company",
    "location": "London, UK",
    "role": "Software Engineer"
  }
}

Batch precompute

Send mode: "precompute" with candidates (array) instead of candidate. Provide exactly one of candidate or candidates. Maximum 50 candidates per request.

POST/api/v1/analyses
{
  "mode": "precompute",
  "language": "en",
  "client": {
    "id": "client_company_123",
    "first_name": "Jane",
    "last_name": "Smith",
    "company": "Acme Recruiting"
  },
  "candidates": [
    {
      "id": "candidate_456",
      "first_name": "John",
      "last_name": "Doe",
      "company": "Example Company",
      "location": "London, UK",
      "role": "Software Engineer"
    },
    {
      "id": "candidate_789",
      "first_name": "Alex",
      "last_name": "Nguyen",
      "company": "Example Company",
      "location": "Berlin, DE",
      "role": "Product Manager"
    }
  ]
}

202 Accepted (batch)

202 Accepted
{
  "items": [
    {
      "id": "cmqp23kgg00067gk0rh6jol5o",
      "status": "queued",
      "candidate_id": "candidate_456",
      "created_at": "2026-06-29T12:00:00.000Z"
    },
    {
      "id": "cmqp23kgg00067gk0rh6jol5p",
      "status": "queued",
      "candidate_id": "candidate_789",
      "created_at": "2026-06-29T12:00:00.000Z"
    }
  ]
}

Poll or fetch each returned id with GET /api/v1/analyses/{id}. When status is completed, report and metadata are populated. That is how you retrieve the ready report.

Precompute is capped per partner (1,000 net-new runs per UTC day and 10 concurrent in-flight). Exceeding a cap returns 429 Too Many Requests with error precompute-cap-exceeded and Retry-After. Cache or in-flight hits do not count toward these caps. Live runs are exempt.

Get analysis (poll & retrieve report)

Use GET /api/v1/analyses/{id} with the same X-API-Key header and the id from the create (or precompute) response. This single endpoint both polls in-progress runs and returns the completed report.

When status is completed, the response includes the full report object plus metadata (including pdf_download_url). There is no separate "get report" endpoint. Stop polling and render or open that payload. See Completed analysis for a full example.

While status is queued or processing, each GET response includes Retry-After: 10. Wait at least 10 seconds before your next request.

Stop polling when status is completed, failed, or canceled.

GET/api/v1/analyses/{id}
{
  "id": "cmqp23kgg00067gk0rh6jol5o",
  "status": "processing",
  "candidate_id": "candidate_456",
  "stage": "enrichment",
  "created_at": "2026-06-29T12:00:00.000Z",
  "updated_at": "2026-06-29T12:00:20.000Z",
  "quick_signal": {
    "level": "Green",
    "reason": "Identity supported by multiple matching signals.",
    "identityConfidence": "Medium"
  },
  "signals": [
    {
      "statement": "Senior engineer at Example Company since 2021.",
      "sourceType": "web",
      "sourceUrl": "https://example.com/…",
      "reliability": "High"
    }
  ],
  "report": null,
  "metadata": null,
  "error": null
}

Fields that populate while processing

quick_signalPreliminary identity signal (Green, Orange, or Red) with a short reason: available once enrichment begins.
signalsLive web signals discovered during enrichment. The array grows as external searches complete.
stageCurrent pipeline stage: identity → enrichment → report → done.
reportFull Candidate Intelligence report: populated only when status is completed. This is the report payload to display or store.
metadataReport metadata: populated only when status is completed. Includes the signed hosted-report link (pdf_download_url) and the cached / cached_at reuse flags.

Status values

queuedAccepted and waiting to start.
processingIn progress: poll for quick_signal, signals, and stage updates.
completedReport ready: use this GET response as your retrieved report (report and metadata are populated).
failedAnalysis failed: error is populated.
canceledAnalysis was canceled via DELETE /api/v1/analyses/{id} or reached a terminal cancel state.

Cancel an analysis

DELETE /api/v1/analyses/{id} stops a queued or in-progress analysis when a recruiter leaves the candidate profile or dismisses a running report. Use the same X-API-Key header as POST and GET.

If the analysis is already completed, failed, or canceled, the endpoint returns the current resource unchanged. No additional charge or side effects.

DELETE/api/v1/analyses/{id}
// No request body: include X-API-Key header only

200 OK

Returns the analysis resource with status canceled. Partial quick_signal or signals may be present if cancellation happened mid-pipeline. Stop polling once status is canceled.

200 OK
{
  "id": "cmqp23kgg00067gk0rh6jol5o",
  "status": "canceled",
  "candidate_id": "candidate_456",
  "stage": "enrichment",
  "created_at": "2026-06-29T12:00:00.000Z",
  "updated_at": "2026-06-29T12:00:25.000Z",
  "quick_signal": null,
  "signals": [],
  "report": null,
  "metadata": null,
  "error": null
}

Report-ready webhooks

As an alternative to polling, TieTalent can push a signed HTTP notification to an endpoint registered for your integration the moment an analysis reaches a final state: report_ready when a report completes (live, precompute, or a cached reuse all count) or report_failed on a terminal failure.

Webhooks complement polling, they never replace it. Treat GET /api/v1/analyses/{id} as authoritative at all times and keep polling in place as a fallback for anything missed.

Webhook endpoints are registered, rotated and monitored for you by TieTalent. There is no partner self-serve setup. Contact your integration contact to have an endpoint added or changed.

Event types

report_readyA final report is ready: covers live runs, precompute runs, and cache-reuse completions alike.
report_failedThe run reached a terminal failure.

Event envelope

Every delivery is a JSON object shaped like the examples below. id is generated once per event and reused on every retry of that same event. Use it as your idempotency key when deduplicating.

api_environment mirrors the label of the API key that authenticated the run (Production, Staging, or Test): the same value shown in your admin API key list. A key only ever delivers to the webhook endpoint registered under its own label.

report_ready payload
{
  "id": "evt_1a2b3c4d5e6f7890",
  "type": "report_ready",
  "created_at": "2026-07-30T14:45:21.650Z",
  "api_environment": "Production",
  "data": {
    "analysis_id": "cmqp23kgg00067gk0rh6jol5o",
    "candidate_id": "candidate_456",
    "client_id": "client_company_123",
    "status": "completed",
    "report_url": "https://intelligence.tietalent.com/api/v1/analyses/cmqp23kgg00067gk0rh6jol5o",
    "pdf_download_url": "https://intelligence.tietalent.com/api/ats/reports/cmqp23kgg00067gk0rh6jol5o/pdf?sig=…"
  }
}
report_failed payload
{
  "id": "evt_9f8e7d6c5b4a3210",
  "type": "report_failed",
  "created_at": "2026-07-30T14:45:21.650Z",
  "api_environment": "Production",
  "data": {
    "analysis_id": "cmqp23kgg00067gk0rh6jol5p",
    "candidate_id": "candidate_789",
    "client_id": "client_company_123",
    "status": "failed",
    "report_url": "https://intelligence.tietalent.com/api/v1/analyses/cmqp23kgg00067gk0rh6jol5p",
    "pdf_download_url": null,
    "error_code": "internal_error"
  }
}

data fields

analysis_idThe same id you would GET via /api/v1/analyses/{id}.
candidate_idYour own candidate.id from the original request: not a TieTalent-internal identifier.
client_idYour own client.id from the original request.
statuscompleted or failed, matching the analysis resource's status.
report_urlThe authed GET /api/v1/analyses/{id} URL: fetch it with your X-API-Key to retrieve the full report.
pdf_download_urlThe signed hosted-report link, same as metadata.pdf_download_url on the GET response. Present on report_ready, null on report_failed.
error_codePresent only on report_failed events: a stable, machine-readable code. Never exposes an internal AI provider or infrastructure detail.
This is a thin "ready" pointer only: no report body, no verdict, and no candidate PII travels in the webhook. Fetch the full report over the existing authed GET using the ids above.

Verifying the signature

Every delivery carries an X-CI-Signature header in the form below. The signed content is {timestamp}.{raw_request_body}, HMAC-SHA256 with the whsec_... secret issued for your endpoint.

X-CI-Signature header

X-CI-Signature: t=1732963521,v1=5d6f2c8a9e1b7340c6a2f5e8b1d9a047c3b6e2f1a8d5c9b4e7f2a1d6c3b8e5f0

During a secret rotation window the header may carry two v1= values: one signed with the outgoing secret, one with the incoming secret. Accept a match against either.

Reject any delivery whose t= timestamp is more than 5 minutes from your own clock: this is your replay-attack defense.

Verifying the signature (pseudocode)

function isValidSignature(header, rawBody, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(
    header.split(",").map((part) => part.split("=").map((s) => s.trim())),
  );
  const timestamp = Number(parts.t);
  if (Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) return false;

  const expectedSignature = hmacSha256Hex(secret, `${timestamp}.${rawBody}`);
  const candidateSignatures = header
    .split(",")
    .filter((part) => part.startsWith("v1="))
    .map((part) => part.slice(3));

  return candidateSignatures.some((signature) => timingSafeEqual(signature, expectedSignature));
}

Delivery semantics

  • At-least-once delivery: a 2xx response within 5 seconds counts as success; anything else retries with exponential backoff and jitter, roughly 10 attempts over about 24 hours, then the event is dead-lettered.
  • Duplicate and out-of-order deliveries are expected: dedupe on id and never assume delivery order across events.
  • If a webhook is ever missed, delayed, or duplicated, your existing polling fallback keeps your state consistent with the authed GET.

Completed analysis

Returned when status is completed. The report below is an HR-type example and abridged: see Report types & fields for the full field list and the Agency-type example.

Fresh report (metadata.cached: false)

JSON200 OK
{
  "id": "clx_analysis_id",
  "status": "completed",
  "candidate_id": "candidate_456",
  "stage": "done",
  "created_at": "2026-06-29T12:00:00.000Z",
  "updated_at": "2026-06-29T12:00:45.000Z",
  "quick_signal": {
    "level": "Green",
    "reason": "Identity supported by multiple matching signals.",
    "identityConfidence": "Medium"
  },
  "signals": [
    {
      "statement": "…",
      "sourceType": "web",
      "sourceUrl": "https://example.com/…",
      "reliability": "High"
    }
  ],
  "report": {
    "report_type": "hr",
    "candidateName": "John Doe",
    "profileHeadline": "Software Engineer",
    "profileCompany": "Example Company",
    "profileLocation": "London, UK",
    "sourcesCheckedCount": 24,
    "identity": {
      "status": "Confirmed",
      "confidence": "High",
      "confidenceReason": "…",
      "risk": { "level": "Low", "reason": "…" }
    },
    "recommendation": {
      "decision": "Go with validation",
      "confidence": "Medium",
      "confidenceNote": "Identity verified · signals consistent",
      "reason": "…",
      "nextStepPills": [
        { "variant": "confirmed", "label": "Role and tenure verified" },
        { "variant": "validate", "label": "Validate team leadership scope" }
      ]
    },
    "bottomLine": {
      "headline": "…",
      "detail": "…"
    },
    "keyTakeaways": {
      "standsOut": [{ "label": "…", "detail": "…" }],
      "needsChecking": [{ "label": "…", "detail": "…" }]
    },
    "surprisingInsights": [
      { "title": "…", "text": "…", "source": "…", "polarity": "Favorable" }
    ],
    "externalBackgroundAssessment": [
      { "claim": "…", "summary": "…", "sourceReference": "…", "evidenceBadge": "high" },
      { "claim": "…", "summary": "…", "evidenceBadge": "not_found" }
    ],
    "externalProfileTags": [
      { "kind": "catalog", "id": "linkedin_verified" },
      { "kind": "catalog", "id": "no_adverse_signals" }
    ],
    "roleFit": {
      "bestSuited": ["…"],
      "considerCarefully": ["…"]
    },
    "interviewQuestions": [{ "question": "…", "hint": "Explores: …" }],
    "alertLevel": "Green",
    "externalDataConfidence": "Medium"
  },
  "metadata": {
    "report_id": "clx_analysis_id",
    "candidate_id": "candidate_456",
    "language": "en",
    "generated_at": "2026-06-29T12:00:45.000Z",
    "pdf_download_url": "https://intelligence.tietalent.com/api/ats/reports/{id}/pdf?sig=…",
    "cached": false,
    "cached_at": null,
    "report_type": "hr"
  },
  "error": null
}

Cached report (metadata.cached: true)

JSON200 OK
{
  "id": "clx_new_analysis_id",
  "status": "completed",
  "candidate_id": "candidate_456",
  "stage": "done",
  "created_at": "2026-07-15T12:00:00.000Z",
  "updated_at": "2026-07-15T12:00:00.500Z",
  "quick_signal": { "…": "…" },
  "signals": [{ "…": "…" }],
  "report": { "…": "…" },
  "metadata": {
    "report_id": "clx_new_analysis_id",
    "candidate_id": "candidate_456",
    "language": "en",
    "generated_at": "2026-07-15T12:00:00.500Z",
    "pdf_download_url": "https://intelligence.tietalent.com/api/ats/reports/{id}/pdf?sig=…",
    "cached": true,
    "cached_at": "2026-07-15T12:00:00.500Z",
    "report_type": "hr"
  },
  "error": null
}

The metadata object

metadata.pdf_download_url is a signed link that opens the full hosted TieTalent report (the same report design as the web app); the PDF export can be downloaded from that view. Treat the link as confidential. Anyone holding it can open the report.

metadata.cached is true when an existing report was reused instead of generating a new one (see Report reuse logic); cached_at then carries the reuse timestamp, otherwise it is null.

metadata.report_type (hr or agency) tells you which report shape the report object follows: see Report types & fields. It is set once for your integration by TieTalent and cannot be overridden per request.

Verdicts & compatibility

report.recommendation.decision is the headline verdict of the report. It is always one of the four values below.

recommendation.decision: possible values

"Proceed with confidence"
"Go with validation"
"Requires Validation (Signals flagged)"
"Requires Validation (Insufficient data)"

Map each verdict to one of three UI states:

Suggested mapping (JavaScript)

function toUiState(decision) {
  switch (decision) {
    case "Proceed with confidence":
      return "proceed";
    case "Go with validation":
      return "validation";
    case "Requires Validation (Signals flagged)":
    case "Requires Validation (Insufficient data)":
      return "requires_validation";
    default:
      return "requires_validation";
  }
}
Best practice: switch on the full string with a safe default of requires_validation so any unexpected value degrades gracefully instead of breaking your UI.

Report types & fields

Every partner account has a default report_type (hr or agency) set for you by TieTalent when your integration is approved (hr is the default). You can override it for a single call (see below). The type used for a given report is always echoed back as metadata.report_type and report.report_type. Field names are camelCase.

Forward compatibility: new fields may be added to either report type over time. Ignore unknown fields and treat every field as nullable unless listed under Core fields below.

Per-call override

Pass an optional report_type field ("hr" or "agency") on POST /api/v1/analyses to use that type for a single call, regardless of your partner account's default. Omit it to keep using your default. The override is not persisted. It applies only to that call. An invalid value returns 400 Bad Request with error invalid-report-type. report_type is also part of the cache key. Requesting a different type than a prior cached run for the same candidate always triggers a fresh report.

Request with report_type override

{
  "language": "en",
  "client": {
    "id": "client_company_123",
    "first_name": "Jane",
    "last_name": "Smith",
    "company": "Acme Recruiting"
  },
  "candidate": {
    "id": "candidate_456",
    "first_name": "John",
    "last_name": "Doe",
    "company": "Example Company",
    "location": "London, UK",
    "role": "Software Engineer"
  },
  "report_type": "agency"
}

Core fields (present on both report types)

report_typehr or agency: which shape this report object follows.
candidateNameCandidate name as resolved by the analysis.
profileHeadline / profileCompany / profileLocationHeader lines for display: role/title, current company, and location. Optional.
sourcesCheckedCountNumber of external search results consulted for the report. Optional.
identityIdentity resolution: status (Confirmed, Likely, Ambiguous, Unknown), confidence, confidenceReason, and risk (level, reason).
recommendationThe verdict: decision (see Verdicts & compatibility), confidence, reason, evidence[], confidenceNote (short evidence headline), and nextStepPills[] (evidence-state pills with variant and label).
bottomLineThe report's opening verdict: headline (one decisive sentence) and detail (1-2 sentences of supporting context).
keyTakeawaysstandsOut[] and needsChecking[] lists of (label, detail) items.
surprisingInsightsUp to 3 cards (title, text, source, polarity): polarity is Favorable or Concern.
externalBackgroundAssessmentEvidence table rows (claim, summary, evidenceBadge, sourceReference?) checking CV/profile claims against external signals: gap-inclusive, so a row with evidenceBadge not_found means no external signal was found for that claim.
externalProfileTagsCatalog-only tags from the source_presence and adverse_signal_status groups: see Tags below.
alertLevelOverall alert level: Green, Yellow, Orange, or Red.
externalDataConfidenceConfidence in the external data behind the report: High, Medium, or Low.

hr-only fields

Present only when report_type is hr. Absent (not null, not present) on agency reports.

roleFitbestSuited[] and considerCarefully[]: role/organisation contexts this profile suits vs. contexts needing more validation.
interviewQuestionsSuggested interview questions: (question, hint).

agency-only fields

Present only when report_type is agency. Absent (not null, not present) on hr reports.

bestFitTagsCatalog tags describing where this profile sits: see Tags below.
takeItForward"Worth knowing if you take this forward": worthItFor[] (plain-sentence reasons) and reflectionQuestions[] (question, answer).

Example hr report object

report (report_type: "hr")

{
  "report_type": "hr",
  "candidateName": "John Doe",
  "profileHeadline": "Software Engineer",
  "profileCompany": "Example Company",
  "profileLocation": "London, UK",
  "sourcesCheckedCount": 24,
  "identity": {
    "status": "Confirmed",
    "confidence": "High",
    "confidenceReason": "…",
    "risk": { "level": "Low", "reason": "…" }
  },
  "recommendation": {
    "decision": "Go with validation",
    "confidence": "Medium",
    "confidenceNote": "Identity verified · signals consistent",
    "reason": "…",
    "nextStepPills": [
      { "variant": "confirmed", "label": "Role and tenure verified" },
      { "variant": "validate", "label": "Validate team leadership scope" }
    ]
  },
  "bottomLine": {
    "headline": "…",
    "detail": "…"
  },
  "keyTakeaways": {
    "standsOut": [{ "label": "…", "detail": "…" }],
    "needsChecking": [{ "label": "…", "detail": "…" }]
  },
  "surprisingInsights": [
    { "title": "…", "text": "…", "source": "…", "polarity": "Favorable" }
  ],
  "externalBackgroundAssessment": [
    { "claim": "…", "summary": "…", "sourceReference": "…", "evidenceBadge": "high" },
    { "claim": "…", "summary": "…", "evidenceBadge": "not_found" }
  ],
  "externalProfileTags": [
    { "kind": "catalog", "id": "linkedin_verified" },
    { "kind": "catalog", "id": "no_adverse_signals" }
  ],
  "roleFit": {
    "bestSuited": ["…"],
    "considerCarefully": ["…"]
  },
  "interviewQuestions": [{ "question": "…", "hint": "Explores: …" }],
  "alertLevel": "Green",
  "externalDataConfidence": "Medium"
}

Example agency report object

report (report_type: "agency")

{
  "report_type": "agency",
  "candidateName": "John Doe",
  "profileHeadline": "Software Engineer",
  "profileCompany": "Example Company",
  "profileLocation": "London, UK",
  "sourcesCheckedCount": 24,
  "identity": {
    "status": "Confirmed",
    "confidence": "High",
    "confidenceReason": "…",
    "risk": { "level": "Low", "reason": "…" }
  },
  "recommendation": {
    "decision": "Go with validation",
    "confidence": "Medium",
    "confidenceNote": "Identity verified · signals consistent",
    "reason": "…",
    "nextStepPills": [
      { "variant": "confirmed", "label": "Role and tenure verified" },
      { "variant": "validate", "label": "Validate team leadership scope" }
    ]
  },
  "bottomLine": {
    "headline": "…",
    "detail": "…"
  },
  "keyTakeaways": {
    "standsOut": [{ "label": "…", "detail": "…" }],
    "needsChecking": [{ "label": "…", "detail": "…" }]
  },
  "surprisingInsights": [
    { "title": "…", "text": "…", "source": "…", "polarity": "Favorable" }
  ],
  "externalBackgroundAssessment": [
    { "claim": "…", "summary": "…", "sourceReference": "…", "evidenceBadge": "high" },
    { "claim": "…", "summary": "…", "evidenceBadge": "not_found" }
  ],
  "externalProfileTags": [
    { "kind": "catalog", "id": "linkedin_verified" },
    { "kind": "catalog", "id": "no_adverse_signals" }
  ],
  "bestFitTags": [
    { "kind": "catalog", "id": "sales_leadership" },
    { "kind": "catalog", "id": "b2b_saas" }
  ],
  "takeItForward": {
    "worthItFor": ["…"],
    "reflectionQuestions": [{ "question": "…", "answer": "…" }]
  },
  "alertLevel": "Green",
  "externalDataConfidence": "Medium"
}

Enumerations

Enum values

identity.status                        Confirmed | Likely | Ambiguous | Unknown
*.confidence                           High | Medium | Low
identity.risk.level                    Low | Medium | High
nextStepPills[].variant                confirmed | validate | partial | insufficient | conflict
surprisingInsights[].polarity          Favorable | Concern
externalBackgroundAssessment[]
  .evidenceBadge                       high | single | validate | not_found
alertLevel                             Green | Yellow | Orange | Red

Tags

externalProfileTags and bestFitTags are catalog-only for this API (every tag carries a stable snake_case id you can switch on. Tag ids are stable API values and are not localized) map them to your own labels or humanize the id.

Tag shape

// externalProfileTags and bestFitTags are catalog-only for this API:
// every tag is a stable snake_case id from the catalogs below.
{ "kind": "catalog", "id": "linkedin_verified" }

externalProfileTags: catalog ids by group

// group: source_presence
linkedin_verified · press_coverage_found · podcast_appearances
company_registry_confirmed · funding_database_found · alumni_record_confirmed
personal_website_found · speaking_engagements_found · published_content_found
social_media_presence · patent_or_ip_record_found · industry_body_membership

// group: adverse_signal_status
no_adverse_signals · adverse_signal_flagged · multiple_adverse_signals

bestFitTags: catalog ids by group (agency reports only)

// group: functional_strength
fundraising_leadership · brand_and_partnerships · team_leadership
operational_execution · product_strategy · commercial_development
technical_execution · external_representation · content_and_thought_leadership
data_and_analytics · legal_and_compliance · finance_and_pnl_ownership
business_development · go_to_market_strategy · sales_leadership

// group: sector_fit
sustainability_sector · luxury_and_lifestyle · b2b_saas
purpose_driven_business · early_stage_startup · enterprise · healthcare
fintech · deep_tech · consumer_and_retail · education
proptech_and_real_estate · logistics_and_supply_chain · international_markets

// group: organisation_type
founder_stage_company · scale_up_series_a_c · large_enterprise
turnaround_or_transformation · ngo_or_non_profit · pe_or_vc_backed
family_business

// group: role_type
c_suite_or_founder_role · senior_leadership · individual_contributor
external_facing_role · operational_role · player_coach

// group: geographic_fit
switzerland · dach_region · western_europe · north_america
asia_pacific · middle_east · latin_america · international

Submit feedback on a report

POST /api/v1/analyses/{id}/feedback lets your recruiters rate a completed report (1 to 5 stars, optional tags, and optional free text) so TieTalent can track report quality on your side of the integration.

The endpoint upserts on client.id plus the report id: submitting again for the same client and report overwrites the previous rating, tags and text. There is no revision history.

POST/api/v1/analyses/{id}/feedback
{
  "client": {
    "id": "client_company_123",
    "first_name": "Jane",
    "last_name": "Smith",
    "company": "Acme Recruiting"
  },
  "rating": 4,
  "feedback": "Helped me shortlist quickly, would have liked more sourcing links.",
  "tags": ["saved_me_time", "good_signal_quality"]
}

Request fields

clientRequired. Same client object as POST /api/v1/analyses: identifies which of your users is giving feedback.
ratingRequired. Integer from 1 to 5.
feedbackOptional. Free-text comment, up to 2000 characters.
tagsOptional. Up to 5 canonical tag ids from the catalog below: invalid values or an out-of-range rating return a 4xx with a clear message.

Feedback tag catalog

Tags are grouped by rating band and swap depending on the rating you send: render your own UI for these, but submit only the canonical ids so feedback stays analyzable across languages.

Canonical tag ids by rating band

// 1-2 stars
missing_info · something_was_wrong · signals_felt_weak
too_generic · hard_to_trust

// 3 stars
useful_but_missing_detail · right_idea_wrong_emphasis
some_signals_felt_off · wanted_more_sources

// 4-5 stars
saved_me_time · helped_me_decide · good_signal_quality
easy_to_read · trustworthy

200 OK

Returns the stored feedback, echoing back the current rating, tags and text on file for that client and report.

200 OK
{
  "report_id": "cmqp23kgg00067gk0rh6jol5o",
  "rating": 4,
  "feedback": "Helped me shortlist quickly, would have liked more sourcing links.",
  "tags": ["saved_me_time", "good_signal_quality"],
  "updated_at": "2026-07-21T12:00:00.000Z"
}

Privacy & security

Reports are decision-support tools only and must not be used as the sole basis for hiring decisions. Human review and independent assessment are always required.
Each partner integration is isolated by API key. You can only access analyses created with your credentials.
Use your client.id and candidate.id to map analyses to records in your ATS.
Optional CV text in the request is used for the analysis and is not stored as a separate document; the generated report (which may reflect CV content) is retained encrypted so it can be served back to your integration.
Data is stored in EU-region infrastructure with encryption at rest.
Candidate Intelligence provides recommendations and validation signals but does not make automated hiring decisions on behalf of users.
Data processing follows the principles of data minimization and purpose limitation.

⚖️ AI Compliance Notice

Candidate Intelligence is designed to support recruiter decision-making, not replace it. Hiring decisions remain the responsibility of the employer and should always include appropriate human review and oversight.

Partner Program

Start integrating Candidate Intelligence

Request access and we will activate your partner API credentials. Integration typically takes less than a day.