Skip to main content
This resource is also /contacts. /candidates is a permanent alias that keeps working unchanged; the newer name is the one to reach for in new code. See Resource names.

Overview

A contact is the person on the other end of a conversation. The Contacts API creates them, keeps them up to date, and finds them again. A contact may be associated with one or more jobs, or with none at all — outside hiring, none is the normal case.

Resource Structure

Free-form metadata: anything you want to keep about a contact for your own use — resume URL, LinkedIn profile, skills — goes in metadata as key-value pairs. It is never validated and never read by an agent.Custom fields are a different thing, and they are the half an agent can speak: values defined in your company catalog, validated on write, and addressable as {{contact.<key>}}. Those live in fields — see Update Contact.
The contact schema also declares analysisCount, interviewCount and links, and they are not currently returned by any endpoint — nothing populates them. They are left out of the structure above deliberately; treat them as absent rather than as zero, and count a contact’s conversations with List Conversations.

Required Scopes

The legacy aliases (read:candidates, write:candidates, delete:candidates) work identically and stay valid on keys that already carry them — see Scopes and Permissions.

A Request Helper

Every JavaScript example below goes through this helper rather than calling fetch directly. It does the two things a bare fetch does not: it gives the request a deadline, and it treats a non-2xx answer as a failure. Without the first, a request to a stalled service never settles; without the second, response.json() parses an error body and the code carries on as though it had a contact.
The Python examples use requests, whose timeout argument is the equivalent — pass it on every call, and check response.raise_for_status() before reading the body.

Creating Contacts

Basic Contact Creation

A contact can be created with or without a job. Without one, the contact simply exists on its own and jobs can be attached later.

A Fuller Contact

Listing Contacts

List All Contacts

Filter by Job

Filter by Status

Search Contacts

Updating Contacts

Partial Update

Update Status

Update Job Assignments

Status Management

Available Statuses

status is yours to move as your own process moves — InstaView does not act on it. The five values predate the neutral vocabulary and keep their hiring names, because they are the values the API accepts.

Status Workflow

Multiple Job Assignments

A contact can be associated with several jobs through jobIds, so one person can be tracked across more than one opening.
Job associations: jobIds is the array to manage. jobId (singular) is kept for backward compatibility and holds the first of them.

Deleting Contacts

This is a hard delete, and it cascades. The contact goes, and so does every conversation they had — transcripts, recordings, analyses — along with their job assignments. None of it is readable through the API afterwards, and no endpoint brings it back. Export what you need first. See Delete Contact.
GDPR: this is the deletion the API offers, and the one to reach for on an erasure request. Deleted rows are archived internally first, for our own compliance obligations, and that archive is not reachable through the API — see Delete Contact before promising a data subject that nothing remains anywhere.

Bulk Delete

Common Patterns

Importing Contacts from an ATS

Duplicate Detection

Rolling Up a Contact’s Calls

Resume Processing

Validation Rules

string
required
First name (1-100 characters)
string
required
Last name (1-100 characters)
string
required
GDPR expiry date in ISO 8601 format (must be in the future, e.g., “2026-11-16”)
string
Valid email address (at least email or phoneNumber required)
string
Phone number in E.164 format (+1234567890) (at least email or phoneNumber required)
string
UUID of the job to associate with (optional - must exist and belong to your company if provided)
array
Array of job UUIDs for multi-job assignments (used in update operations)
object
Custom key-value pairs for extensibility (max 10KB, max 5 levels deep, max 50 keys). Store additional fields like resumeUrl, skills, education, etc.
string
"male" or "female". Used for gender-aware addressing on the call (Slovak and Czech formal titles, for instance). Auto-detected from the name when omitted.
string
The contact’s anonymized CV as plain text. Send the raw text as cvText on create or update and it is anonymized for you using Google Gemini.
array
Previous employment, one entry per job. Each entry can carry a reference to call about it:
  • id (string, optional): UUID of the work history record
  • companyName (string, required): Name of the company/employer
  • candidatePosition (string, required): The role held there. Keeps its original name, which is the name the API accepts.
  • referenceName (string, optional): Name of the reference to call
  • referencePhone (string, required): That reference’s phone number in E.164 format (e.g. +1234567890)
  • startDate (string, optional): Job start date in calendar format (yyyy-MM-dd)
  • endDate (string, optional): Job end date in calendar format (yyyy-MM-dd)

Error Scenarios

Errors answer with the flat body described in Error Handling: a statusCode, a message, a traceId, and — on a rejected request body — an errors array with one entry per rejected constraint.
A phone number is unique per company, across every job. An email address is not — two contacts may share one.

Documents

A contact can hold documents an agent may look up during a call — a cover letter, application notes, and the contact’s own processed CV. They are managed under /contacts/{id}/documents with the same three-step presigned upload as an agent’s knowledge base.
1

Reserve a slot

POST /contacts/{id}/documents/uploads with fileName, mimeType and the file’s exact sizeBytes. Both the slot and the bytes are reserved against your company’s limits from this moment.
2

Upload the file

PUT the bytes to the returned uploadUrl with the returned contentType. No API key on this request.
3

Complete the upload

POST /contacts/{id}/documents/{documentId}/complete. The file is verified and the document becomes READY.
Two things distinguish contact documents from agent documents:
  • The CV appears on its own. Once a CV has been processed, the listing shows a document with source: "CV". It is produced from the CV’s anonymized text and cannot be renamed or deleted through the API — deactivate it (PATCH with isActive: false) to keep it out of calls.
  • Two limits. At most 5 uploaded documents per contact, and a plan-tiered ceiling on your company’s total contact-document storage. Both are reserved when an upload is started, and the 400 you get when the company ceiling is the problem names the bytes in use, the ceiling and the size requested.
Listing a document does not put it on a call. The agent must have contextConfig.useContactContext enabled. With it off, calls run exactly as they did before, documents or not.
Contact documents follow the contact’s retention: when the contact reaches its GDPR expiry date, its documents are deleted with it, stored files and voice-provider copies included. See the Contact Documents reference for the full endpoint set.

Best Practices

Validate Data

Validate email and phone formats before submission

Handle Duplicates

Implement duplicate detection logic

Update Status

Keep each contact’s status current as your process moves

Secure Resume URLs

Use signed URLs with expiration for resume access

Next Steps

Conversations

Start a conversation with a contact

Jobs

Learn about job management

API Reference

The full Contacts API reference

Best Practices

Production integration patterns