Guides
Submitting and Uploading Feedback
Register audio recordings, upload directly to S3-compatible storage, and confirm upload completion.
Voiceflow allows customers to register voice notes, upload audio directly to S3-compatible storage, and track processing status. Audio never passes directly through the application server.
Upload Flow Overview#
Submitting feedback follows a three-step client flow:
- Register: The customer client calls the API to validate file metadata and create a pending record. The API returns a signed S3 upload URL.
- Direct Upload: The client sends the raw audio file directly to object storage using an HTTP
PUTrequest. - Confirm: The client notifies the API that the upload has finished. The API verifies the uploaded file's existence and size before queuing background processing.
All customer feedback routes are mounted on feedbackRouter under the /api/feedback path and require authenticated customer credentials.
Registering Feedback#
To register an audio recording, submit a POST /api/feedback request. The request body is validated against registerFeedbackSchema.
Validation Rules and Constraints#
mimeType: Allowed audio MIME types areaudio/webm,audio/mp4, andaudio/ogg. Values containing codecs (such asaudio/webm;codecs=opus) are trimmed to the base MIME type.sizeBytes: An integer between 1 andMAX_SIZE_BYTES(2,097,152 bytes or 2 MB).durationMs: An integer between 1 andMAX_DURATION_MS(30,500 milliseconds).consent: Must explicitly betrue.languageHint(optional): One of the supported Sarvam language codes defined inSPEECH_LANGUAGES(such asen-IN,hi-IN,ta-IN,te-IN,mr-IN, etc.).
Example Request#
Registration Response#
The API creates a record with UPLOADING status, assigns a storage path scoped to the user ({userId}/{id}.{ext}), and generates a pre-signed URL via createUploadUrl.
{
"id": "a4b595ca-938b-4cce-91f8-0e1ce33a8cfa",
"uploadUrl": "https://bucket.s3.region.amazonaws.com/user_123/a4b595ca-938b-4cce-91f8-0e1ce33a8cfa.webm?X-Amz-..."
}
Direct Upload to Storage#
The uploadUrl is an S3 pre-signed PUT URL that expires after 15 minutes (900 seconds). The pre-signed URL binds both ContentType and ContentLength. When performing the upload, the HTTP request must use the exact declared MIME type and file byte size.
Confirming Upload Completion#
After the direct upload to storage succeeds, call POST /api/feedback/:id/complete to confirm completion.
When executing completeUpload, the server verifies the upload:
- Ensures the recording belongs to the authenticated customer and is currently in
UPLOADINGstatus. If already confirmed, it returns anINVALID_STATE(409) error. - Verifies the file in object storage. If the file is missing or the stored size does not match
sizeBytes, it returns anUPLOAD_MISSING(400) error. - Updates the database status to
UPLOADED. - Emits a
feedback/uploadedevent to Inngest to trigger the background processing pipeline (see Processing Feedback and Scheduled Cleanup).
A successful confirmation returns HTTP status 202 Accepted:
{
"status": "UPLOADED"
}
Tracking Customer Feedback#
Customers can retrieve their submitted feedback entries and monitor processing progress.
Fetch a Specific Recording#
Send a GET /api/feedback/:id request:
The response returns public details including processing status and transcriptions. Sentiment analysis details are restricted to admins and omitted from customer responses:
{
"id": "a4b595ca-938b-4cce-91f8-0e1ce33a8cfa",
"status": "COMPLETED",
"durationMs": 12000,
"errorCode": null,
"createdAt": "2025-01-15T10:00:00.000Z",
"completedAt": "2025-01-15T10:00:25.000Z",
"transcription": {
"originalText": "नमस्ते, सेवा बहुत अच्छी थी।",
"englishText": "Hello, the service was very good.",
"languageCode": "hi-IN"
}
}
List Customer Recordings#
Send a GET /api/feedback request to retrieve a paginated list of recordings for the authenticated customer:
The endpoint returns up to 20 items per page ordered newest to oldest (createdAt: "desc", id: "desc"), alongside a nextCursor value:
{
"items": [
{
"id": "a4b595ca-938b-4cce-91f8-0e1ce33a8cfa",
"status": "COMPLETED",
"durationMs": 12000,
"errorCode": null,
"createdAt": "2025-01-15T10:00:00.000Z",
"completedAt": "2025-01-15T10:00:25.000Z",
"transcription": {
"originalText": "Great support experience.",
"englishText": "Great support experience.",
"languageCode": "en-IN"
}
}
],
"nextCursor": null
}