Authentication
The BlackLab API supports two authentication methods. Choose the one that fits your integration.
API Keys
For server-to-server integrations. Pass your secret key in the Authorization header.
Authorization: Bearer sk_live_your_api_key_here
API keys carry full permissions of the owning account. Never expose them in client-side code.
OAuth 2.0
For third-party applications acting on behalf of users. Supports Authorization Code and Client Credentials flows.
| Parameter | Value |
|---|---|
| Authorization URL | https://app.blacklab.studio/oauth/authorize |
| Token URL | https://api.blacklab.studio/v1/oauth/token |
| Scopes | mastering:read mastering:write assets:write account:read |
Base URL
# Production
https://api.blacklab.studio/v1
# Sandbox
https://sandbox.api.blacklab.studio/v1
All endpoints use HTTPS. HTTP requests are rejected. The sandbox environment mirrors production with synthetic responses.
Rate Limits
Rate limits use a sliding window algorithm. Limits are applied per API key.
| Tier | Requests/min | Burst |
|---|---|---|
| Free | 60 | 10 |
| Pro | 300 | 50 |
| Enterprise | 1,000 | 200 |
Rate limit headers are included in every response:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1700000060
Idempotency
To safely retry requests without creating duplicate resources, include an Idempotency-Key header on POST requests.
curl -X POST https://api.blacklab.studio/v1/mastering/jobs \
-H "Authorization: Bearer sk_live_xxx" \
-H "Idempotency-Key: unique-request-id-123" \
-H "Content-Type: application/json" \
-d '{"input_url": "...", "preset": "balanced"}'
- Keys must be unique UUIDs or strings up to 255 characters.
- Idempotency keys expire after 24 hours.
- Replayed requests return the original response with a
X-Idempotent-Replayed: trueheader. - If the original request is still processing, a
409 Conflictis returned.
POST /v1/mastering/jobs
Submit an audio file for AI mastering. Returns a job object with status and estimated completion time.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
input_url |
string | Yes | URL of the source audio file (WAV, FLAC, AIFF, MP3). |
preset |
string | No | Mastering preset. One of: balanced, warm, bright, loud. Default: balanced. |
format |
string | No | Output format: wav, flac, mp3. Default: wav. |
sample_rate |
integer | No | Output sample rate: 44100, 48000, 96000. Default: source rate. |
webhook_url |
string | No | URL to receive webhook events for this job. |
reference_url |
string | No | Reference track URL for style matching. |
Example Request
curl -X POST https://api.blacklab.studio/v1/mastering/jobs \
-H "Authorization: Bearer sk_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"input_url": "https://storage.example.com/my-track.wav",
"preset": "balanced",
"format": "wav",
"sample_rate": 44100,
"webhook_url": "https://myapp.com/webhooks/blacklab"
}'
Example Response 201 Created
{
"id": "job_abc123def456",
"status": "queued",
"preset": "balanced",
"format": "wav",
"sample_rate": 44100,
"estimated_seconds": 120,
"credits_charged": 1,
"created_at": "2025-01-15T10:30:00Z",
"output_url": null
}
GET /v1/mastering/jobs/{id}
Retrieve the current status and details of a mastering job.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id |
string | The job ID returned from the create endpoint. |
Example Response 200 OK
{
"id": "job_abc123def456",
"status": "completed",
"preset": "balanced",
"format": "wav",
"sample_rate": 44100,
"credits_charged": 1,
"created_at": "2025-01-15T10:30:00Z",
"completed_at": "2025-01-15T10:32:04Z",
"output_url": "https://cdn.blacklab.studio/output/job_abc123def456.wav",
"output_expires_at": "2025-01-16T10:32:04Z"
}
Possible status values: queued, processing, completed, failed, cancelled.
POST /v1/assets/upload-url
Generate a pre-signed upload URL. Use this to upload audio files directly to BlackLab storage before submitting a mastering job.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
filename |
string | Yes | Original filename with extension. |
content_type |
string | Yes | MIME type: audio/wav, audio/flac, audio/mpeg, audio/aiff. |
size_bytes |
integer | Yes | File size in bytes. Maximum 200 MB (209715200). |
Example Response 200 OK
{
"upload_url": "https://storage.blacklab.studio/uploads/...",
"asset_url": "https://storage.blacklab.studio/assets/asset_xyz789.wav",
"expires_at": "2025-01-15T11:00:00Z"
}
Upload the file with a PUT request to upload_url, then pass asset_url as the input_url to the mastering endpoint.
Webhooks
BlackLab delivers real-time event notifications to your configured webhook endpoints via HTTPS POST.
Setup
- Register a webhook URL in your app settings.
- BlackLab signs each payload with HMAC-SHA256 using your webhook secret.
- Verify the
X-BlackLab-Signatureheader before processing. - Respond with
200 OKwithin 10 seconds. Failed deliveries are retried up to 5 times with exponential backoff.
# Verify webhook signature (Python)
import hmac, hashlib
def verify_webhook(payload_bytes, signature, secret):
expected = hmac.new(
secret.encode(), payload_bytes, hashlib.sha256
).hexdigest()
return hmac.compare_digest(f"sha256={expected}", signature)
Webhook Events
| Event | Description | Payload |
|---|---|---|
job.done |
Mastering job completed successfully. | Full job object with output_url. |
job.failed |
Mastering job failed. Credits are refunded. | Job object with error field. |
credits.low |
Account credit balance below threshold. | {"balance": 3, "threshold": 5} |
Example Webhook Payload
{
"event": "job.done",
"timestamp": "2025-01-15T10:32:04Z",
"data": {
"id": "job_abc123def456",
"status": "completed",
"output_url": "https://cdn.blacklab.studio/output/job_abc123def456.wav"
}
}
Error Catalog
All errors follow a consistent JSON structure:
{
"error": {
"code": "insufficient_credits",
"message": "Your account does not have enough credits for this operation.",
"param": null,
"doc_url": "https://developers.blacklab.studio/docs#err-insufficient-credits"
}
}
| Code | HTTP Status | Description |
|---|---|---|
authentication_required |
401 | Missing or invalid API key / token. |
forbidden |
403 | Valid credentials but insufficient permissions. |
not_found |
404 | Requested resource does not exist. |
validation_error |
422 | Request body failed validation. Check param field. |
insufficient_credits |
402 | Not enough credits to complete the operation. |
rate_limited |
429 | Too many requests. Retry after Retry-After seconds. |
idempotency_conflict |
409 | A request with this idempotency key is already in progress. |
file_too_large |
413 | Uploaded file exceeds the 200 MB limit. |
unsupported_format |
415 | Audio format is not supported. |
internal_error |
500 | Unexpected server error. Contact support if persistent. |
HTTP Status Codes
| Status | Meaning |
|---|---|
| 200 | Success. |
| 201 | Resource created successfully. |
| 204 | Success, no content returned. |
| 400 | Bad request. Check your request body. |
| 401 | Authentication required. |
| 402 | Payment / credits required. |
| 403 | Forbidden. Insufficient permissions. |
| 404 | Resource not found. |
| 409 | Conflict (idempotency or state). |
| 413 | Payload too large. |
| 415 | Unsupported media type. |
| 422 | Validation error. |
| 429 | Rate limited. |
| 500 | Internal server error. |