Files

Endpoints for the standalone file import flow — one file becomes one Marvin interview or document. For a walkthrough with runnable code, see Importing files to Marvin.

EndpointScope
GET /api/v1/developer/import/filesfile:write
POST /api/v1/developer/import/files/initializefile:write
POST {upload_url} (S3, not Marvin)
POST /api/v1/developer/import/files/{wav_key}/completefile:write
GET /api/v1/developer/import/files/{wav_key}/statusfile:write

You'll also need GET /import/projects (project:read) to resolve a project_id. Marvin endpoints here are rate limited to 20 requests/minute per API key.


POST /api/v1/developer/import/files/initialize #

Creates a wav record and returns a wav_key plus a presigned S3 upload URL.

bash
curl -s -X POST "$BASE_URL/api/v1/developer/import/files/initialize" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "project_id": 42,
    "file_name": "customer-interview.mp4"
  }' | python3 -m json.tool

Parameters:

FieldTypeRequiredDescription
project_idintegerYesID from the list projects response
file_namestringYesOriginal filename including extension (max 500 chars). Extension determines media type and content type.

Response (201):

json
{
  "wav_key": "a1b2c3d4-...",
  "upload_url": "https://s3.amazonaws.com/bucket/",
  "upload_fields": {
    "key": "developer-uploads/10/a1b2c3d4-.../media.mp4",
    "Content-Type": "video/mp4",
    "x-amz-credential": "...",
    "policy": "...",
    "x-amz-signature": "..."
  },
  "links": {
    "complete": "/api/v1/developer/import/files/a1b2c3d4-.../complete",
    "status": "/api/v1/developer/import/files/a1b2c3d4-.../status"
  }
}

Unsupported extensions return 400. See Supported file types.


POST {upload_url} (S3) #

Upload directly to S3 via the presigned POST from initialize. All upload_fields must be sent as form fields before the file.

bash
curl -X POST "https://s3.amazonaws.com/bucket/" \
  -F "key=developer-uploads/10/a1b2c3d4-.../media.mp4" \
  -F "Content-Type=video/mp4" \
  -F "x-amz-credential=..." \
  -F "policy=..." \
  -F "x-amz-signature=..." \
  -F "file=@customer-interview.mp4"

Size limits (enforced by the presigned policy):

TypeMax size
Audio / video10 GB
Documents / images500 MB

Presigned URLs expire after 1 hour. To get a fresh URL, call initialize again — this creates a new wav_key, as there is no retry endpoint for files.


POST /api/v1/developer/import/files/{wav_key}/complete #

Marvin checks that the object exists in S3, sets the file URL on the wav, and kicks off processing (transcription for audio/video, extraction for documents, etc.).

bash
export WAV_KEY="a1b2c3d4-..."

curl -s -X POST "$BASE_URL/api/v1/developer/import/files/$WAV_KEY/complete" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

Response (200):

json
{
  "wav_key": "a1b2c3d4-...",
  "status": "processing"
}

If the file is missing from S3:

json
{
  "error": "File not found in S3. Upload the file before calling complete."
}

Idempotency: Calling complete again when the file is already linked returns 200 with "status": "processing".


GET /api/v1/developer/import/files/{wav_key}/status #

Returns the current processing status for the uploaded file. Poll until status is completed or error.

bash
curl -s "$BASE_URL/api/v1/developer/import/files/$WAV_KEY/status" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

Response:

json
{
  "wav_key": "a1b2c3d4-...",
  "name": "customer-interview.mp4",
  "status": "completed",
  "file_url": "https://s3.amazonaws.com/bucket/developer-uploads/10/a1b2c3d4-.../media.mp4",
  "created_at": "2026-07-14T08:30:00+00:00"
}

Status values:

StatusMeaning
pending_uploadInitialize succeeded; file not yet uploaded / not completed
processingFile linked; transcription or document processing in progress
completedReady to use in Marvin
errorProcessing failed (error_flag on the file)
recording(Rare for this API) Active recording session

Typical audio/video transcription latency depends on duration and queue load.


GET /api/v1/developer/import/files #

Lists files imported through this API, scoped to projects accessible to your API key, newest first.

bash
curl -s "$BASE_URL/api/v1/developer/import/files?limit=50&offset=0" \
  -H "Authorization: Bearer $TOKEN" | python3 -m json.tool

Response:

json
{
  "files": [
    {
      "wav_key": "a1b2c3d4-...",
      "name": "customer-interview.mp4",
      "project_id": 42,
      "status": "completed",
      "created_at": "2026-07-14T08:30:00+00:00"
    }
  ],
  "count": 1,
  "next": null,
  "previous": null
}

This also includes surveys imported via the CSVs API — a survey is itself backed by a wav record, so it shows up here too (wav_key is the survey's underlying wav, not the upload_key/survey_key from the surveys endpoint). status uses the same values as poll for status, including pending_upload for files whose upload never completed (surveys are never pending_upload — their status reflects whether column mapping is complete).

Requires file:write scope (the same scope used by initialize/complete/status — there is no separate read-only scope for files in this API).

Pagination: results are paginated with limit/offset query params (default and max limit is 50). count is the total number of matching files; next/previous are full URLs to the adjacent page, or null when there isn't one.


Supported file types #

Extensions accepted by file_name (case-insensitive):

CategoryExtensions
Videomp4, mov, avi, webm, mkv, m4v, wmv, mpeg
Audiomp3, m4a, wav, flac, ogg, aac, aiff, aif, amr
Documentspdf, ppt, pptx, doc, docx, xls, xlsx, txt
Imagespng, jpg, jpeg, gif, bmp, tiff, webp

Errors #

HTTPWhen
400Invalid/missing body, unsupported extension, or file missing in S3 on complete
403Missing required scope, or project creation disabled for the team
404Project not accessible / not found, or unknown wav_key
429Rate limit exceeded (20 req/min per API key on these endpoints)

See Troubleshooting for fixes.