Skip to main content

Poll analysis status

GET 

/api/v1/speech/analyze/:requestId

Returns the current status of a previously submitted analysis. Safe to poll repeatedly. The minimum enforced interval is 10 seconds for non-terminal statuses; faster polls return 429.

Response shape varies by status:

  • queued / processing: lightweight status payload, Retry-After header set
  • success / partial: full result payload with scores, analysis, transcript
  • failed: terminal with error.code and error.message

The id does not expire — you can stop and resume polling later. (The path parameter accepts the same value returned as id on submit.)

Webhook delivery (push instead of poll)​

If you register one or more webhook endpoints for your account, every terminal Speech run is also delivered to them as a signed POST — so you can react to results push-style instead of polling. Register and test endpoints from the webhooks console in your dashboard.

  • Events: speech.completed (a success or partial run) and speech.failed (a failed run). There is no separate partial event — a degraded run arrives as speech.completed with status: "partial" and a non-empty warnings[] array naming what degraded.
  • Body: the same result fields the poll endpoint returns for that run (scores, analysis, transcript for a completed run; error for a failed one), wrapped with an event name. It never contains fields the poll response omits.
  • Signature: each delivery carries an X-CVDM-Signature header of the form t=<unix-ts>,v1=<hex-hmac-sha256>. Recompute the HMAC over <t>.<raw-body> with your signing secret and compare in constant time before trusting the payload.
  • Retries: a non-2xx or timeout is retried up to 3 times with exponential backoff. Delivery is best-effort — the poll endpoint remains the source of truth if every attempt fails.

Example speech.completed (partial) body:

{
"event": "speech.completed",
"id": "req_1705412345678_abc123",
"status": "partial",
"timestamp": "2026-04-20T10:06:15.015Z",
"processingTimeMs": 62473,
"scoringMethod": "ml_hybrid",
"audio": { "durationMs": 180000, "languageCode": "eng", "requestedLanguage": "en", "speakerCount": 2 },
"scores": { "vocabulary": 4.37, "fluency": 4.63, "accent": null, "overall": 4.42, "cefrLevel": "C2" },
"warnings": [ { "code": "ACCENT_SCORE_UNAVAILABLE", "message": "Accent analysis was unavailable for this run." } ],
"degraded": ["ACCENT_SCORE_UNAVAILABLE"]
}

Example speech.failed body:

{
"event": "speech.failed",
"id": "req_1705412345678_abc123",
"status": "failed",
"timestamp": "2026-04-20T10:06:15.015Z",
"processingTimeMs": 42100,
"error": { "code": "TRANSCRIPTION_FAILED", "message": "Transcription failed: audio appears corrupted." }
}

Request​

Responses​

Current state of the run.