Endpoints
All endpoints require Authorization: Bearer hd_ext_<your-key>. See Authentication.
Create a Project
POST /api/projects — Submit audio for transcription and optional AI processing.
The server downloads the audio (and optional job sheet) from the provided presigned URLs, re-uploads to internal storage, creates the project, and queues the transcription job.
Template Resolution
Templates determine the DOCX formatting applied after transcription. Resolution order:
- Use
templateIdif provided. - Auto-select based on
projectType+jurisdiction(and extracted job sheet metadata). - Fall back to the configured system default template.
- If no template is available → 422.
Call GET /api/templates to see available templates and their IDs.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
title | string | ✅ | Display title. Overridden by AI-extracted case title if a job sheet is provided. |
audioUrl | string (URL) | ✅ | Presigned S3 URL to the audio file (MP3, WAV, M4A, WebM, MP4). Valid for ≥ 5 minutes. |
jobSheetUrl | string (URL) | — | Presigned S3 URL to a job sheet (DOCX, TXT, CSV) for AI metadata extraction. |
description | string | — | Free-text description shown in the project list. |
projectType | "legal" | "general" | — | Affects template auto-select. Default: "general". |
templateId | string | — | Specific template ID. Skips auto-select if provided. |
jurisdiction | string | — | State code for template auto-select (e.g. "CA", "NY"). Also extracted from job sheet. |
additionalDetails | string | — | Context for the AI pipeline (max 1000 chars). |
autoProcessEnabled | boolean | — | Run AI formatting + proofreading after transcription. Default: true. |
externalRef | string | — | Your reference ID (order number, job ID) stored with the project. |
jobId | string | — | Job ID for filtering a multi-case CSV job sheet. If the ID is not found or matches multiple rows, returns 422. Ignored for non-CSV job sheets. |
metadata | object | — | Case metadata. Merged with job sheet extraction; caller values take precedence. |
metadata fields (all optional):
{
"caseNumber": "2024-CV-00123",
"courtName": "Superior Court of California",
"date": "2024-06-15",
"plaintiffs": ["Alice Smith"],
"defendants": ["Bob Jones"],
"attorneys": ["John Counsel"],
"witnesses": ["Mary Witness"]
}Response 201
{
"projectId": "j57abc123def456",
"transcriptId": "k89xyz789ghi012"
}| Field | Description |
|---|---|
projectId | Use in subsequent status calls. |
transcriptId | Convex transcript record ID. |
warning | Present if transcription could not be started (project is still created). |
Status Codes
| Code | Meaning |
|---|---|
201 | Project created, transcription queued. |
400 | Missing title or audioUrl, invalid JSON. |
401 | Invalid or revoked API key. |
403 | templateId not found or not accessible. |
422 | No template available for the requested project type, or jobId filtering failed (not found, multiple matches, malformed CSV, or blank jobId). |
429 | Rate limit exceeded. See Retry-After header. |
500 | Unexpected server error. |
502 | Failed to download audio from audioUrl (upstream error). |
Example
curl -X POST https://app.heydonna.chat/api/projects \
-H "Authorization: Bearer hd_ext_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"title": "Smith v. Jones — Order 98765",
"audioUrl": "https://s3.amazonaws.com/bucket/audio.mp3?X-Amz-Signature=...",
"jobSheetUrl": "https://s3.amazonaws.com/bucket/jobsheet.docx?X-Amz-Signature=...",
"projectType": "legal",
"jurisdiction": "CA",
"externalRef": "ORG-JOB-98765",
"metadata": {
"caseNumber": "2024-CV-00123",
"courtName": "Superior Court of California"
}
}'Get Project Status
GET /api/projects/:id/status — Poll transcription and AI pipeline status.
This endpoint is not rate-limited. Poll at most once every 5–10 seconds. Transcription typically takes 3–15 minutes depending on audio length.
Path Parameter
| Parameter | Description |
|---|---|
id | Project ID from POST /api/projects. |
Response 200
{
"projectId": "j57abc123def456",
"status": "processing",
"externalRef": "ORG-JOB-98765",
"transcripts": [
{
"transcriptId": "k89xyz789ghi012",
"title": "Smith v. Jones Deposition",
"status": "processing",
"audioDuration": null,
"progress": 45,
"pipelineStage": null,
"pipelineProgressMessage": null,
"pipelineStageStartedAt": null
}
]
}Project status values:
| Value | Description |
|---|---|
created | Project created; transcription not yet started. |
processing | Transcription or AI pipeline active. |
transcribed | Transcription complete; AI pipeline not yet run (or disabled). |
ready | AI pipeline complete; transcript ready for editing. |
shared | Transcript shared with another user. |
finalized | Terminal state — work complete. |
failed | Processing failed. Contact support to retry. |
Transcript status values:
| Value | Description |
|---|---|
processing | Active (transcription or pipeline running). |
transcribing | Transcription stage in progress. |
formatting | AI formatting stage in progress. |
proofreading | AI proofreading stage in progress. |
ready_for_review | Proofreading done; formatting not yet applied. |
ready | Final state — transcript complete. |
error | An error occurred (check pipelineProgressMessage). |
Transcript pipelineStage values (internal pipeline stages, autoProcessEnabled: true):
| Value | Description |
|---|---|
queued | Pipeline queued; not yet started. |
v0 | First pipeline stage (formatting). |
v1 | Second pipeline stage. |
v2 | Third/final pipeline stage. |
cancelled | Pipeline was cancelled by the user. |
Status Codes
| Code | Meaning |
|---|---|
200 | Status returned. |
400 | Invalid project ID format. |
401 | Invalid or revoked API key. |
404 | Project not found or not accessible with this key. |
500 | Unexpected server error. |
Polling Pattern
import time, requests, os
project_id = "j57abc123def456"
headers = {"Authorization": f"Bearer {os.environ['HEYDONNA_API_KEY']}"}
while True:
resp = requests.get(
f"https://app.heydonna.chat/api/projects/{project_id}/status",
headers=headers,
)
resp.raise_for_status()
data = resp.json()
print(f"Status: {data['status']}")
if data["status"] in ("ready", "transcribed", "finalized", "failed"):
break
time.sleep(15) # Poll every 15 secondsList Templates
GET /api/templates — List formatting templates available to your API key.
Returns system templates and templates owned by your account. Use the returned id
as templateId in POST /api/projects to bypass auto-select.
Response 200
{
"templates": [
{
"id": "j57abc123def456",
"name": "Standard Deposition — California",
"jurisdiction": "CA",
"category": "deposition",
"proceedingType": "deposition",
"isDefault": true,
"hasTranscriptSection": true
},
{
"id": "m12pqr345stu678",
"name": "EUO Template",
"jurisdiction": null,
"category": null,
"proceedingType": "euo",
"isDefault": false,
"hasTranscriptSection": true
}
]
}Template fields:
| Field | Description |
|---|---|
id | Use as templateId in POST /api/projects. |
name | Human-readable display name. |
jurisdiction | State/jurisdiction the template is optimized for (null = all). |
category | Template category ("deposition", "hearing", etc.). |
proceedingType | Proceeding type used for auto-select matching. |
isDefault | Whether this is the default for its proceeding type. |
hasTranscriptSection | Whether the template includes a formatted transcript section. |
Status Codes
| Code | Meaning |
|---|---|
200 | Template list returned (may be empty). |
401 | Invalid or revoked API key. |
429 | Rate limit exceeded. |
500 | Unexpected server error. |
Example
curl https://app.heydonna.chat/api/templates \
-H "Authorization: Bearer hd_ext_YOUR_KEY"