Skip to content
  • There are no suggestions because the search field is empty.

Crosschq Interview Partner API

Enabling Crosschq Partner API for Interview Agent

The Crosschq Interview Partner APIs allow third-party platforms to programmatically integrate with Crosschq's AI Interview product. Through these APIs, partners can:

  1. List the AI interview agents configured for their organization.
  2. Request a new AI interview for a candidate.
  3. Retrieve the status, score, and report URL of an interview.
  4. Cancel an interview that is still in progress.
  5. Receive webhook notifications when an interview's status changes.

Sandbox testing is available — please reach out to support@crosschq.com to request access or to enable the Partner API on your organization.

The Partner API base URL is provisioned during partner onboarding — reach out to your Crosschq contact to retrieve it. Throughout this document, <URL> represents the base URL you receive at onboarding.


Table of Contents


Authentication

All requests are authenticated with a Crosschq-issued API key, sent in the Authorization header on every request. API keys are scoped to a single organization. To obtain or rotate credentials, contact your Crosschq account manager or support@crosschq.com.


Endpoints

List interview agents

<URL>/interview-plans [GET]

Returns the active AI interview agents configured for your organization. Results are paginated using an opaque cursor.

Query Parameters:

  • limit: (optional) number of results per page. Default 25, maximum 100.
  • cursor: (optional) opaque pagination token returned by a previous response in next_cursor. Omit on the first call.
  • search: (optional) case-insensitive substring filter applied to the plan's name.

Response:

{
  "data": [
    {
      "id": "6f3a9b2c-1d4e-4a2f-9b8a-2c5d4e6f7a8b",
      "name": "Software Engineer Screen",
      "job_title": "Software Engineer",
      "created": "2026-01-04T14:22:10Z",
      "modified": "2026-01-12T09:05:33Z"
    }
  ],
  "next_cursor": "eyJjcmVhdGVkIjoiMjAyNi0wMS0wNFQxNDoyMjoxMFoifQ=="
}

When there are no more pages, next_cursor is null.


Create AI Interview

<URL>/ai-interviews [POST]

Creates a new AI interview for a candidate against one of your organization's active interview agents. The candidate is notified by email and/or SMS based on the agent's configuration.

Request Headers:

  • Authorization: (required) your partner API key (UUID). The legacy X-API-Key header is also accepted.
  • Idempotency-Key: (optional, strongly recommended) unique client-supplied string used to safely retry this request. See Idempotency.
  • Content-Type: application/json

Request Body:

  • interview_plan_id: (required) UUID of the interview agent to use. The agent must be active and fully configured.
  • candidate: (required) candidate dictionary.
    • first_name: (required) candidate's first name.
    • last_name: (required) candidate's last name.
    • email: (required) candidate's email address.
    • phone: (optional) candidate's phone number in E.164 format (for SMS-enabled plans).
    • external_id: (optional) your system's identifier for the candidate. Used for deduplication.
  • external_id: (optional) your system's identifier for this interview request. Used for deduplication and returned on all responses.
  • metadata: (optional) free-form JSON object that is stored with the interview and returned on webhook payloads.
  • skip_duplicate_check: (optional) boolean. When true, a new interview is created even if an interview already exists for the same candidate and plan. Defaults to false.
{
  "interview_plan_id": "6f3a9b2c-1d4e-4a2f-9b8a-2c5d4e6f7a8b",
  "candidate": {
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "jane.doe@example.com",
    "phone": "+15551234567",
    "external_id": "candidate-ext-123"
  },
  "external_id": "interview-ext-789",
  "metadata": {
    "requisition_id": "REQ-4421",
    "source": "partner-ats"
  },
  "skip_duplicate_check": false
}

Response (201 Created):

{
  "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
  "status": "requested",
  "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
  "created_at": "2026-05-13T17:42:08Z",
  "external_id": "interview-ext-789",
  "candidate": {
    "id": "11223344-5566-7788-99aa-bbccddeeff00",
    "external_id": "candidate-ext-123"
  }
}

Notes:

  • The interview_plan_id must reference an agent that is active and fully configured. Requests targeting unconfigured or archived plans return 404.
  • external_id on both the interview and candidate is stored and is used to detect duplicate submissions when skip_duplicate_check is false.

Error Responses:

  • 400 — validation_error: missing required field, invalid value, plan not fully configured, or a duplicate interview already exists for this candidate/plan combination (when skip_duplicate_check is false).
  • 404 — not_found: the interview agent does not exist or is not active.

Get Interview Status

<URL>/interviews/{interview_id} [GET]

Returns the current status of an interview, including score and report URL once the interview is completed.

Path Parameters:

interview_id: (required) UUID of the interview, as returned by POST /ai-interviews.

 

Response (200 OK):

{
  "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
  "external_id": "interview-ext-789",
  "status": "completed",
  "score": 8.5,
  "report_url": "https://app.crosschq.com/report/a1b2c3d4-e5f6-4789-9abc-def012345678",
  "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
  "created_at": "2026-05-13T17:42:08Z",
  "started_at": "2026-05-13T18:01:15Z",
  "completed_at": "2026-05-13T18:28:47Z",
  "candidate": {
    "id": "11223344-5566-7788-99aa-bbccddeeff00",
    "external_id": "candidate-ext-123"
  }
}

Fields scorereport_urlstarted_at, and completed_at are null until the interview reaches the corresponding stage.

Possible status values:

  • requested — interview has been created and the candidate has been notified.
  • accepted — candidate accepted the invitation but has not started the interview.
  • in_progress — candidate has started the interview.
  • partial — interview ended before completion (for example, the candidate dropped off).
  • generating_report — interview has finished and the report is being generated.
  • pending_confirmation — interview is waiting for human confirmation before being finalized.
  • completed — interview is finished and a report is available.
  • declined — candidate declined the interview.
  • canceled — interview was cancelled by the partner or the candidate.
  • auto_canceled — interview was automatically cancelled.

Error Responses:

  • 404 — not_found: the interview does not exist or does not belong to your organization.

Cancel Interview

<URL>/interviews/{interview_id}/cancel [POST]

Cancels an interview that is still in progress. Only interviews in requestedin_progress, or accepted status can be cancelled.

Path Parameters:

  • interview_id: (required) UUID of the interview to cancel.

Request Body (optional):

  • reason: (optional) free-text reason describing why the interview is being cancelled. Stored with the interview and included in the cancellation webhook.
{
  "reason": "Position filled"
}

Response (200 OK):

{
  "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
  "status": "canceled",
  "cancelled_at": "2026-05-13T19:12:04Z",
  "reason": "Position filled"
}

Error Responses:

  • 400 — interview_not_cancellable: the interview is in a status that does not allow cancellation (for example, already completed or canceled).
  • 404 — not_found: the interview does not exist or does not belong to your organization.

Webhooks

Crosschq can deliver real-time notifications to your platform whenever the status of an interview changes. Webhook URLs and authentication are configured per-organization — contact support@crosschq.com to enable a webhook endpoint.

Supported configuration:

  • HTTP method: POST (default) or PUT.
  • Authentication: none, HTTP Basic, or a raw Authorization header value, depending on what your endpoint expects.
  • Timeout: 10 seconds per delivery attempt.
  • Retries: failed deliveries are retried up to 3 times with exponential backoff, up to a maximum of 300 seconds between attempts.

Event: interview.status_changed

A single event type is delivered each time an interview transitions to one of the statuses listed below. The data block uses the same schema as the GET /interviews/{interview_id} response, so a partner can consume both interchangeably.

Webhook payload shape:

{
  "event": "interview.status_changed",
  "timestamp": "2026-05-13T18:28:47Z",
  "data": {
    "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
    "external_id": "interview-ext-789",
    "status": "<status value>",
    "score": null,
    "report_url": null,
    "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "created_at": "2026-05-13T17:42:08Z",
    "started_at": null,
    "completed_at": null,
    "candidate": {
      "id": "11223344-5566-7788-99aa-bbccddeeff00",
      "external_id": "candidate-ext-123"
    }
  }
}

Below are example payloads for each supported status transition.

Status: requested

Fires immediately after the interview is created and the candidate is notified.

{
  "event": "interview.status_changed",
  "timestamp": "2026-05-13T17:42:09Z",
  "data": {
    "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
    "external_id": "interview-ext-789",
    "status": "requested",
    "score": null,
    "report_url": null,
    "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "created_at": "2026-05-13T17:42:08Z",
    "started_at": null,
    "completed_at": null,
    "candidate": {
      "id": "11223344-5566-7788-99aa-bbccddeeff00",
      "external_id": "candidate-ext-123"
    }
  }
}

Status: in_progress

Fires when the candidate begins the interview.

{
  "event": "interview.status_changed",
  "timestamp": "2026-05-13T18:01:15Z",
  "data": {
    "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
    "external_id": "interview-ext-789",
    "status": "in_progress",
    "score": null,
    "report_url": null,
    "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "created_at": "2026-05-13T17:42:08Z",
    "started_at": "2026-05-13T18:01:15Z",
    "completed_at": null,
    "candidate": {
      "id": "11223344-5566-7788-99aa-bbccddeeff00",
      "external_id": "candidate-ext-123"
    }
  }
}

Status: completed

Fires when the interview has finished and the report is available. score and report_url are populated.

{
  "event": "interview.status_changed",
  "timestamp": "2026-05-13T18:28:47Z",
  "data": {
    "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
    "external_id": "interview-ext-789",
    "status": "completed",
    "score": 8.5,
    "report_url": "https://app.crosschq.com/report/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "created_at": "2026-05-13T17:42:08Z",
    "started_at": "2026-05-13T18:01:15Z",
    "completed_at": "2026-05-13T18:28:47Z",
    "candidate": {
      "id": "11223344-5566-7788-99aa-bbccddeeff00",
      "external_id": "candidate-ext-123"
    }
  }
}

Status: canceled

Fires when the interview is cancelled by the partner (via POST /interviews/{id}/cancel) or by the candidate.

{
  "event": "interview.status_changed",
  "timestamp": "2026-05-13T19:12:04Z",
  "data": {
    "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
    "external_id": "interview-ext-789",
    "status": "canceled",
    "score": null,
    "report_url": null,
    "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "created_at": "2026-05-13T17:42:08Z",
    "started_at": null,
    "completed_at": null,
    "candidate": {
      "id": "11223344-5566-7788-99aa-bbccddeeff00",
      "external_id": "candidate-ext-123"
    }
  }
}

Status: auto_canceled

Fires when Crosschq automatically cancels the interview as configured in the organization settings.

{
  "event": "interview.status_changed",
  "timestamp": "2026-05-15T17:42:08Z",
  "data": {
    "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
    "external_id": "interview-ext-789",
    "status": "auto_canceled",
    "score": null,
    "report_url": null,
    "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "created_at": "2026-05-13T17:42:08Z",
    "started_at": null,
    "completed_at": null,
    "candidate": {
      "id": "11223344-5566-7788-99aa-bbccddeeff00",
      "external_id": "candidate-ext-123"
    }
  }
}

Status: declined

Fires when the candidate explicitly declines to take the interview.

{
  "event": "interview.status_changed",
  "timestamp": "2026-05-13T20:05:11Z",
  "data": {
    "interview_id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
    "external_id": "interview-ext-789",
    "status": "declined",
    "score": null,
    "report_url": null,
    "interview_url": "https://app.crosschq.com/interview/a1b2c3d4-e5f6-4789-9abc-def012345678",
    "created_at": "2026-05-13T17:42:08Z",
    "started_at": null,
    "completed_at": null,
    "candidate": {
      "id": "11223344-5566-7788-99aa-bbccddeeff00",
      "external_id": "candidate-ext-123"
    }
  }
}

Idempotency

The POST /ai-interviews endpoint supports the Idempotency-Key header to allow safe retries of interview-creation requests. Include a unique client-generated string (for example, a UUID) on each new request. If the same key is sent again within your organization's request log, the original response is returned without creating a new interview.

curl -X POST <URL>/ai-interviews \
  -H 'Authorization: 00000000-0000-0000-0000-000000000000' \
  -H 'Idempotency-Key: 8a7c2f0e-9b1d-4c3e-b6a7-5e4d3c2b1a09' \
  -H 'Content-Type: application/json' \
  -d '{
    "interview_plan_id": "6f3a9b2c-1d4e-4a2f-9b8a-2c5d4e6f7a8b",
    "candidate": {
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "jane.doe@example.com"
    }
  }'

We recommend always sending an Idempotency-Key when creating interviews so that network failures or retries cannot accidentally produce duplicates.


Rate Limiting

Requests are rate-limited per API key on a fixed one-hour window. The default limit is 3,600 requests per hour. Higher limits are available on request — contact support@crosschq.com.

When the limit is exceeded, the API responds with 429 Too Many Requests and a Retry-After header indicating how many seconds to wait before retrying.

HTTP/1.1 429 Too Many Requests
Retry-After: 1800

{
  "error": "rate_limit_exceeded",
  "message": "Rate limit exceeded.",
  "details": {}
}

Errors

All error responses follow the same JSON structure:

{
  "error": "error_code",
  "message": "Human-readable description.",
  "details": {}
}
  • error: machine-readable error code suitable for branching logic.
  • message: human-readable description for logs and support tickets.
  • details: optional object with extra context (for example, per-field validation errors).
Status Error code Description
400 validation_error The request body is missing a required field or contains an invalid value.
400 interview_not_cancellable The interview cannot be cancelled in its current status.
401 authentication_failed The API key header is missing, invalid, or disabled.
404 not_found The requested resource does not exist or does not belong to your organization.
422 validation_error The request payload failed schema validation. The details.errors array lists the offending fields.
429 rate_limit_exceeded The hourly request limit has been exceeded. Honor the Retry-After header.
500 internal_error An unexpected error occurred on Crosschq's side. Retry with backoff and contact support if it persists.

Support

For API enablement, sandbox access, webhook configuration, custom rate limits, or any other questions about the Crosschq Interview Partner API, please contact support@crosschq.com.