Skip to main content

Async polling flow

The ZenHire API is asynchronous: submit returns immediately, and you poll for results. This page explains why, and how to design your integration around it.

Why async?

Speech analysis runs through several steps — transcription, speaker diarization, candidate detection, then three independent ML scoring pipelines (vocabulary, fluency, accent). Typical end-to-end latency is 2–5 minutes, sometimes longer under load. A synchronous HTTP request would time out on most clients.

The async flow lets you:

  • Submit thousands of audio files in parallel without blocking on any one.
  • Survive client-side restarts — the run id never expires.
  • Safely retry a transient network error on the poll endpoint.

The lifecycle

queued → processing → success | partial | failed
  • queued — the request was accepted but no processing slot was available. The run starts automatically, in FIFO order, when a slot frees up. You see queuePosition in the response.
  • processing — actively running. Retry-After is set on the poll response.
  • success — all three scores produced.
  • partial — at least one score produced, others failed. Credits are charged proportionally.
  • failed — no scores produced. No credits charged. See error.code and error.message.

Use pollIntervalSeconds from the most recent response. If you want to implement your own strategy:

Elapsed since submitInterval
0–2 minutes15 seconds
2–5 minutes30 seconds
5+ minutes60 seconds

Minimum interval per run id is 10 seconds. Faster polls return 429 POLL_RATE_LIMITED — respect the Retry-After header.

When to stop polling

Stop when the status is terminal (success, partial, or failed), or when your budget expires.

The run id never expires. If your client crashes mid-poll, you can pick up the same id hours later and continue polling.

Concurrency and queueing

Default 8 simultaneous processing runs per client (contact support to extend). When you reach that limit, new submissions return 202 Accepted with status: "queued"not an error. Queue position is included in the response.

This means a successful 202 from submit doesn't guarantee your run has started — check the poll endpoint to know when processing begins.

Explainability on the success response

Successful and partial responses include an optional explainability object with plain-language, human-readable summaries of why each score came out the way it did:

{
"explainability": {
"vocab": "Advanced vocabulary with consistent use of C1+ words...",
"fluency": "Fluid delivery at 156 words/min with a strong..."
}
}

Two sentences per dimension, safe to surface directly to end users (hiring managers, candidates, audit reviewers) — no post-processing required. Omitted on failed runs and in rare cases where a per-dimension feature breakdown couldn't be produced, so branch on presence before rendering.

Poll-only across services

This submit-and-poll pattern is the common shape across the platform. Speech, CV DeepMatch, and CV DeepSearch all support a poll-only integration: submit returns a run id, and you poll until a terminal state. No public endpoint is required.

The same cadence rules apply to CV DeepMatch and CV DeepSearch — minimum 10 seconds between polls per id, with 429 + Retry-After on faster polls. See the CV DeepMatch integration guide and CV DeepSearch search guide for poll-vs-webhook details.

Webhooks alternative?

  • Speech API — webhooks are not yet supported. If you need them, let your ZenHire contact know; it's on the roadmap.
  • CV DeepMatch and CV DeepSearch — webhooks are supported as an optional push channel: supply a webhook_url on submit to also receive a signed HMAC callback. Omit it to integrate poll-only.

See in the API reference