Open app

Process private audio from your own systems.

Upload directly to private object storage, process individual files or manifests of up to 50,000 items, and use the same prepaid balance as your CleanWave web account.

curl https://api.cleanwaveaudio.com/v1/projects \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"

Authentication

Server integrations use a generated API key. Keys inherit the web account’s projects and credit balance. Never expose a key in browser or mobile code.

Authorization: Bearer cw_live_...
Content-Type: application/json
01

Request a private upload URL

The API creates the project record and returns a short-lived R2 upload URL. Audio bytes do not pass through the CleanWave API service.

curl -X POST https://api.cleanwaveaudio.com/v1/uploads \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "original_filename": "interview.wav",
    "content_type": "audio/wav",
    "claimed_size_bytes": 8451021
  }'
02

Upload and finalize

Use the returned URL without your CleanWave key. Send every header from the response’s headers object exactly as returned. A successful finalize validates size, container, stream, duration, channels and sample rate.

curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: $UPLOAD_CONTENT_TYPE" \
  --upload-file interview.wav

curl -X POST https://api.cleanwaveaudio.com/v1/uploads/$PROJECT_ID/finalize \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"
03

Start asynchronous analysis

A successful request returns 202 Accepted. Credits are reserved from the same balance used by the web application. Poll the project until it reachesready_for_review or failed.

curl -X POST https://api.cleanwaveaudio.com/v1/projects/$PROJECT_ID/analyze \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"

curl https://api.cleanwaveaudio.com/v1/projects/$PROJECT_ID \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"
04

Review suggestions and export

Analysis returns a transcript, PII detections and suggested redactions. Update the redactions if necessary, then start the asynchronous WAV export. Poll until the project reaches completed and download_ready is true.

curl -X PUT https://api.cleanwaveaudio.com/v1/projects/$PROJECT_ID/redactions \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"redactions":[{
    "entity_type":"phone_number",
    "text":"060123456",
    "start_time":12.4,
    "end_time":14.1,
    "mode":"silence",
    "review_status":"accepted",
    "detection_ids":[]
  }]}'

curl -X POST https://api.cleanwaveaudio.com/v1/projects/$PROJECT_ID/export \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"mode":"silence"}'
05

Download, verify and delete

Save and verify the result before deletion. API downloads do not delete a project automatically. After verification, delete the project to remove its original, output, temporary R2 objects and retained metadata immediately.

curl -L https://api.cleanwaveaudio.com/v1/projects/$PROJECT_ID/download \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY" \
  --output interview-anonymized.wav

curl -X DELETE https://api.cleanwaveaudio.com/v1/projects/$PROJECT_ID \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"
Batch

Stream a manifest of up to 50,000 files

Open an empty batch, append descriptors in fragments of 500–1,000, close the manifest, request bounded upload windows, upload directly to R2, then callprocess once. Every manifest request needs a stable idempotency key.

curl -X POST https://api.cleanwaveaudio.com/v1/batches \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY" \
  -H "Idempotency-Key: import-2026-09-manifest" \
  -H "Content-Type: application/json" \
  -d '{"name":"September import","expected_file_count":50000}'

curl -X POST https://api.cleanwaveaudio.com/v1/batches/$BATCH_ID/items \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY" \
  -H "Idempotency-Key: import-2026-09-chunk-0001" \
  -H "Content-Type: application/json" \
  -d '{"files":[{
    "client_reference":"call-000001",
    "original_filename":"call-000001.wav",
    "content_type":"audio/wav",
    "claimed_size_bytes":8451021
  }]}'

curl -X POST https://api.cleanwaveaudio.com/v1/batches/$BATCH_ID/finalize \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"

curl "https://api.cleanwaveaudio.com/v1/batches/$BATCH_ID/uploads?limit=100&offset=0" \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"

# Upload every item with its returned method, URL and headers.
curl -X PUT "$UPLOAD_URL" \
  -H "Content-Type: $UPLOAD_CONTENT_TYPE" \
  --upload-file call-000001.wav

curl -X POST https://api.cleanwaveaudio.com/v1/batches/$BATCH_ID/process \
  -H "Authorization: Bearer $CLEANWAVE_API_KEY"

Batch workers validate uploaded objects before analysis, so individual/uploads/{project_id}/finalize calls are optional for normal batch processing. Use /retry only after a terminal failed state and/cancel to stop work that has not begun.

v1 · Client API

Complete endpoint reference

The reference below covers the endpoints available to customer integrations. Administrator routes, signed provider callbacks and OIDC-protected scheduler routes are intentionally excluded.

Base URL: https://api.cleanwaveaudio.com. Unless an endpoint is explicitly marked public or browser-only, authenticate it withAuthorization: Bearer $CLEANWAVE_API_KEY.

System

Service status and configuration

GET/health

Process liveness. Public; returns {"status":"ok"}.

GET/ready

Checks PostgreSQL, R2, billing, FFmpeg and FFprobe. Public; returns 503 when a dependency is unavailable.

GET/v1/auth/config

Public browser helper that reports whether Google sign-in is enabled.

GET/v1/auth/google/start?next=/app

Browser-only Google OAuth entry point. Sets a short-lived state cookie and redirects to Google.

GET/v1/auth/google/callback

Browser-only OAuth callback used by Google. Validates state, creates the secure session cookie and redirects back to the application.

GET/v1/config

Authenticated account-facing limits and feature flags, including file, batch, retention, billing and zero-access settings.

GET/v1/auth/me

Returns the current identity and authentication method for a browser session or API key.

POST/v1/auth/logout

Browser-only. Clears the web session. Add ?redirect=true to return to the public site.

Credentials

API key management

Key management requires an authenticated Google web session; a machine key cannot create another key. expires_in_days accepts 1–365 ornull for no expiration.

GET/v1/api-keys

Lists active keys using only their ID, name, prefix, creation, expiration and last-use timestamps.

POST/v1/api-keys

Creates a key from {"name":"Production import","expires_in_days":90}. The full cw_live_… secret appears only in this response.

DELETE/v1/api-keys/{key_id}

Immediately invalidates the key and removes it from the active-key interface.

Credits

Balance and checkout

One credit represents one minute of analyzed audio. Web and API processing draw from the same account balance.

GET/v1/billing/balance

Returns available, reserved and debt values in seconds and credits.

POST/v1/billing/checkout

Creates a Lemon Squeezy checkout. Requires credits, accepted legal terms, the current legal version and immediate-service consent.

{
  "credits": 60,
  "terms_accepted": true,
  "legal_terms_version": "2026-08-13-v2",
  "immediate_service_requested": true
}
Storage

Direct upload lifecycle

POST/v1/uploads

Creates one project and returns a presigned R2 PUT request. JSON fields are described below.

POST/v1/uploads/{project_id}/finalize

Validates an uploaded object and starts its retention clock. Zero-access uploads additionally submit their encryption envelope here.

POST/v1/projects

Legacy multipart upload through the API service. Use only for small or compatibility flows; direct R2 upload is preferred.

original_filename

Required filename ending in .wav, .mp3 or .m4a.

content_type

Required audio MIME type. Use the returned signed header unchanged.

claimed_size_bytes

Required positive byte count, checked again after upload.

redaction_policy

Optional enabled categories and a custom instruction of at most 1,000 characters.

folder_id / folder_name / relative_path

Optional folder metadata; if one is supplied, all three are required.

zero_access

Optional encrypted-browser workflow. Ordinary server integrations should leave it false.

High volume

Batch manifests and processing

POST/v1/batches

Opens an idempotent manifest. Accepts name, optional expected_file_count and optionally up to 1,000 initial file descriptors.

POST/v1/batches/{batch_id}/items

Atomically appends 1–1,000 descriptors. Each fragment requires its own stable Idempotency-Key.

POST/v1/batches/{batch_id}/finalize

Closes intake. The item total must match expected_file_count when it was declared.

GET/v1/batches/{batch_id}

Returns aggregate counts and a page of items. Query: offset ≥ 0, limit 1–500.

GET/v1/batches/{batch_id}/uploads

Returns bounded, short-lived upload requests for a page of items still uploading.

POST/v1/batches/{batch_id}/process

Queues the complete manifest and returns 202. Calling it again while queued or processing does not duplicate the run.

POST/v1/batches/{batch_id}/retry

Queues only failed items from a failed or partially_failed batch.

POST/v1/batches/{batch_id}/cancel

Cancels work that has not started and marks the batch cancelled.

There is currently no customer endpoint to list all batches or delete an entire batch. Delete retained files individually with the project DELETE endpoint.

Results

Projects, review, export and delivery

GET/v1/projects

Lists retained projects owned by the authenticated account.

GET/v1/projects/{project_id}

Returns metadata, progress, transcript, detections, redactions, error and download readiness.

POST/v1/projects/{project_id}/analyze

Queues asynchronous analysis and reserves credits. Returns 202.

PUT/v1/projects/{project_id}/policy

Replaces the redaction policy. A changed policy invalidates prior analysis and export, requiring re-analysis.

PUT/v1/projects/{project_id}/redactions

Replaces the complete reviewed redaction list after analysis. A changed list invalidates an existing export.

POST/v1/projects/{project_id}/export

Queues WAV generation. Optional body: {"mode":"silence"} or {"mode":"beep"}.

GET/v1/projects/{project_id}/download

Downloads the completed anonymized WAV. It does not delete the project automatically.

GET/v1/projects/{project_id}/audio

Streams the retained original for authenticated preview.

GET/v1/downloads/archive?project_ids=…

Builds a temporary ZIP from up to 20 completed projects. Repeat project_ids for multiple files.

DELETE/v1/projects/{project_id}

Immediately removes the project’s entire R2 prefix and retained metadata. Call after a verified download.

Advanced browser protocol

Zero-access confidential processing

These endpoints support CleanWave’s encrypted browser workflow. They are not required for ordinary server-to-server batch integrations and require the documented cryptographic envelopes and an attested confidential worker.

POST/v1/projects/{project_id}/confidential-bind

Binds encrypted upload metadata to an attested worker session.

POST/v1/projects/{project_id}/confidential-ticket

Issues a signed, short-lived worker job ticket.

GET/v1/projects/{project_id}/confidential-review

Returns a short-lived encrypted review download and its envelope.

GET/v1/projects/{project_id}/confidential-original

Returns a short-lived encrypted-original download and its envelope.

POST/v1/confidential/session

Starts an attested confidential session for a project.

GET/v1/confidential/status?project_id=…

Returns worker startup state and queue position.

POST/v1/confidential/process

Relays an encrypted processing request to the confidential worker.

Data model

States and response fields

Project states: uploading, uploaded, analyzing, ready_for_review, exporting, completed, failed, cancelled.

Batch states: creating, ready, queued, processing, completed, partially_failed, failed, cancelled.

Review states: suggested, accepted, rejected. Redaction modes: silence and beep.

{
  "id": "project UUID",
  "original_filename": "interview.wav",
  "file_size_bytes": 8451021,
  "duration_seconds": 584.2,
  "status": "ready_for_review",
  "progress_percent": 100,
  "zero_access": false,
  "redaction_policy": {"enabled_categories": [], "custom_instruction": ""},
  "transcript": {"language": "ro", "text": "…", "words": []},
  "detections": [],
  "redactions": [],
  "download_ready": false,
  "error": null,
  "created_at": "ISO-8601",
  "updated_at": "ISO-8601"
}
Reliability

Errors, idempotency and retries

400 / 422

Malformed request or invalid field. Correct the request; do not retry unchanged.

401 / 403

Missing, invalid, expired or unauthorized credential.

402

Insufficient credits. Purchase credits before retrying analysis.

404

Resource absent or owned by another account.

409

State conflict, reused idempotency key with different content, or operation already active.

413 / 415

File too large or unsupported/invalid audio.

425 / 429

Capacity is starting or rate-limited. Respect Retry-After and use exponential backoff with jitter.

500 / 503

Temporary server or dependency failure. Retry idempotent requests with bounded backoff.

Error bodies contain a safe detail and usually arequest_id. Preserve that ID when contacting support. Replaying an identical batch or fragment idempotency key is safe; changing the payload for an existing key returns 409.

Operations

Limits, polling and retention

  • Files: WAV, MP3 and M4A; maximum 100 MB and 60 minutes per file.
  • Audio: one audio stream, at most two channels, sample rate between 8 kHz and 96 kHz.
  • Batches: maximum 50,000 files; fragments up to 1,000; upload/status pages up to 500.
  • Archives: maximum 20 completed projects per ZIP.
  • Polling: use bounded exponential backoff; do not poll every file continuously.
  • Retention: validated uploads are removed automatically within 24 hours; production targets 23 hours plus scheduled cleanup.
  • Immediate deletion: call DELETE /v1/projects/{id} after verifying the download.
  • Detection: automated PII suggestions can miss content; human review remains recommended for sensitive use cases.

Presigned R2 URLs are short-lived and must be regenerated through the upload window endpoint after expiry. URL expiry does not delete an object already uploaded. All R2 URLs are secrets for their short lifetime and must not be logged or shared.

Operational rules

  • Keep API keys and presigned URLs out of client-side code and logs.
  • Retry a manifest fragment only with its unchanged idempotency key and payload.
  • Verify downloads, then delete projects to minimize retained data.
  • Respect Retry-After and bound upload, polling and processing concurrency.
  • Human review remains recommended for sensitive or high-risk recordings.