{"openapi":"3.1.0","info":{"title":"StemSplit API","description":"Public API for StemSplit - AI-powered stem separation for audio files. Separate vocals, drums, bass, and more from any song.","version":"1.0.0","contact":{"name":"StemSplit Support","url":"https://stemsplit.io/contact"},"x-errors-reference":"https://stemsplit.io/developers/docs#limits","x-api-changelog":"https://stemsplit.io/developers/changelog"},"servers":[{"url":"https://stemsplit.io/api/v1","description":"Production"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Jobs","description":"Stem separation jobs"},{"name":"Denoise Jobs","description":"Standalone voice cleaning / noise removal jobs"},{"name":"SoundCloud","description":"SoundCloud stem separation jobs"},{"name":"YouTube","description":"YouTube stem separation jobs"},{"name":"Upload","description":"File upload"},{"name":"Account","description":"Account and billing"},{"name":"Webhooks","description":"Webhook management"}],"paths":{"/jobs":{"post":{"operationId":"createJob","summary":"Create a stem separation job","description":"Create a new stem separation job from an uploaded file or remote URL.","tags":["Jobs"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobRequest"},"examples":{"fromUpload":{"summary":"From presigned upload","value":{"uploadKey":"uploads/api_xxx/input.mp3","outputType":"BOTH","quality":"BEST","outputFormat":"MP3"}},"fromUrl":{"summary":"From remote URL","value":{"sourceUrl":"https://example.com/song.mp3","outputType":"FOUR_STEMS","quality":"BEST"}}}}}},"responses":{"201":{"description":"Job created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobCreatedResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCreditsError"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"listJobs","summary":"List jobs","description":"List stem separation jobs for the authenticated user.","tags":["Jobs"],"parameters":[{"name":"limit","in":"query","description":"Maximum number of jobs to return (max 100)","schema":{"type":"integer","default":20,"maximum":100}},{"name":"offset","in":"query","description":"Number of jobs to skip for pagination","schema":{"type":"integer","default":0}},{"name":"status","in":"query","description":"Filter by job status","schema":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","EXPIRED"]}}],"responses":{"200":{"description":"Jobs list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/jobs/{id}":{"get":{"operationId":"getJob","summary":"Get job details","description":"Get the status and download links for a specific job.","tags":["Jobs"],"parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/soundcloud-jobs":{"post":{"operationId":"createSoundcloudJob","summary":"Create a SoundCloud stem separation job","description":"Submit a public SoundCloud track URL for stem separation. Output is fixed to vocals + instrumental, MP3, BEST quality. Maximum duration 15 minutes.","tags":["SoundCloud"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateSoundcloudJobRequest"}}}},"responses":{"201":{"description":"SoundCloud job created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoundcloudJobCreatedResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCreditsError"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"listSoundcloudJobs","summary":"List SoundCloud jobs","description":"List SoundCloud stem separation jobs for the authenticated user.","tags":["SoundCloud"],"parameters":[{"name":"limit","in":"query","description":"Maximum number of jobs to return","schema":{"type":"integer","default":20}},{"name":"offset","in":"query","description":"Number of jobs to skip for pagination","schema":{"type":"integer","default":0}},{"name":"status","in":"query","description":"Filter by job status","schema":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","EXPIRED"]}}],"responses":{"200":{"description":"SoundCloud jobs list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoundcloudJobsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/soundcloud-jobs/{id}":{"get":{"operationId":"getSoundcloudJob","summary":"Get SoundCloud job details","description":"Get the status and download links for a specific SoundCloud job.","tags":["SoundCloud"],"parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"string"}}],"responses":{"200":{"description":"SoundCloud job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SoundcloudJobDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/upload":{"post":{"operationId":"getUploadUrl","summary":"Get presigned upload URL","description":"Get a presigned URL for uploading an audio file. Use the returned uploadKey when creating a job.","tags":["Upload"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadRequest"},"example":{"filename":"my-song.mp3"}}}},"responses":{"200":{"description":"Presigned upload URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UploadResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/balance":{"get":{"operationId":"getBalance","summary":"Get credit balance","description":"Get the current credit balance for the authenticated user.","tags":["Account"],"responses":{"200":{"description":"Credit balance","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BalanceResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks":{"post":{"operationId":"createWebhook","summary":"Create a webhook","description":"Register a webhook URL to receive job completion notifications.","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWebhookRequest"},"example":{"url":"https://your-server.com/webhook","events":["job.completed","job.failed"]}}}},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreatedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"listWebhooks","summary":"List webhooks","description":"List all registered webhooks for the authenticated user.","tags":["Webhooks"],"responses":{"200":{"description":"Webhooks list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhooksListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/webhooks/{id}":{"delete":{"operationId":"deleteWebhook","summary":"Delete a webhook","description":"Delete a registered webhook.","tags":["Webhooks"],"parameters":[{"name":"id","in":"path","required":true,"description":"Webhook ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Webhook deleted","content":{"application/json":{"schema":{"type":"object","properties":{"deleted":{"type":"boolean","example":true}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/youtube-jobs":{"post":{"operationId":"createYoutubeJob","summary":"Create a YouTube stem separation job","description":"Submit a YouTube video URL for stem separation.","tags":["YouTube"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateYoutubeJobRequest"}}}},"responses":{"201":{"description":"YouTube job created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/YoutubeJobCreatedResponse"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCreditsError"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"listYoutubeJobs","summary":"List YouTube jobs","description":"List YouTube stem separation jobs for the authenticated user.","tags":["YouTube"],"parameters":[{"name":"limit","in":"query","description":"Maximum number of jobs to return (max 100)","schema":{"type":"integer","default":20,"maximum":100}},{"name":"offset","in":"query","description":"Number of jobs to skip for pagination","schema":{"type":"integer","default":0}},{"name":"status","in":"query","description":"Filter by job status","schema":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","EXPIRED"]}}],"responses":{"200":{"description":"YouTube jobs list","content":{"application/json":{"schema":{"$ref":"#/components/schemas/YoutubeJobsListResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/youtube-jobs/{id}":{"get":{"operationId":"getYoutubeJob","summary":"Get YouTube job details","description":"Get the status and download links for a specific YouTube job.","tags":["YouTube"],"parameters":[{"name":"id","in":"path","required":true,"description":"Job ID","schema":{"type":"string"}}],"responses":{"200":{"description":"YouTube job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/YoutubeJobDetailResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/denoise-jobs":{"post":{"operationId":"createDenoiseJob","summary":"Create a denoise job","description":"Create a standalone noise removal job from an uploaded audio file.","tags":["Denoise Jobs"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDenoiseJobRequest"},"example":{"inputFileName":"podcast-ep1.mp3","inputFilePath":"uploads/api_xxx/podcast-ep1.mp3","inputFileSize":48200000,"durationSeconds":1843,"outputFormat":"MP3"}}}},"responses":{"200":{"description":"Denoise job created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DenoiseJobResponse"},"example":{"jobId":"cm...","status":"PENDING","outputFormat":"MP3","createdAt":"2026-05-28T00:00:00.000Z"}}}},"400":{"description":"Bad request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Insufficient credits","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCreditsError"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}},"get":{"operationId":"listDenoiseJobs","summary":"List denoise jobs","description":"List noise removal jobs for the authenticated user.","tags":["Denoise Jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","description":"Filter by job status","required":false,"schema":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","EXPIRED"]}},{"name":"page","in":"query","description":"Page number (1-based)","required":false,"schema":{"type":"integer","default":1}},{"name":"limit","in":"query","description":"Maximum number of jobs to return","required":false,"schema":{"type":"integer","default":20,"maximum":100}}],"responses":{"200":{"description":"Denoise jobs list","content":{"application/json":{"schema":{"type":"object","properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/DenoiseJobResponse"}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"page":{"type":"integer"},"limit":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/denoise-jobs/{id}":{"get":{"operationId":"getDenoiseJob","summary":"Get denoise job details","description":"Get the status and download link for a specific noise removal job.","tags":["Denoise Jobs"],"security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Denoise job ID","schema":{"type":"string"}}],"responses":{"200":{"description":"Denoise job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DenoiseJobResponse"},"example":{"id":"cm...","status":"COMPLETED","progress":100,"inputFileName":"podcast-ep1.mp3","durationSeconds":1843,"outputFormat":"MP3","outputFilePath":"outputs/...","creditsCharged":1843,"createdAt":"2026-05-28T10:00:00.000Z","completedAt":"2026-05-28T10:00:45.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"description":"Denoise job not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key authentication. Get your API key from Settings > API Keys in your dashboard."}},"responses":{"Unauthorized":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"MISSING_API_KEY","message":"Missing API key. Include 'Authorization: Bearer sk_live_xxx' header."}}}}},"RateLimited":{"description":"Rate limit exceeded","headers":{"X-RateLimit-Limit":{"schema":{"type":"integer"},"description":"Requests allowed per minute"},"X-RateLimit-Remaining":{"schema":{"type":"integer"},"description":"Requests remaining in current window"},"X-RateLimit-Reset":{"schema":{"type":"integer"},"description":"Unix timestamp when rate limit resets"},"Retry-After":{"schema":{"type":"integer"},"description":"Seconds until rate limit resets"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMIT_EXCEEDED","message":"Rate limit exceeded. Try again in 45 seconds."}}}}}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","description":"Error code for programmatic handling"},"message":{"type":"string","description":"Human-readable error message"}},"required":["code","message"]}}},"InsufficientCreditsError":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","example":"INSUFFICIENT_CREDITS"},"message":{"type":"string","example":"Not enough credits for this job."},"requiredSeconds":{"type":"integer","description":"Credits required for this job (in seconds)"},"purchaseUrl":{"type":"string","description":"URL to purchase more credits"}}}}},"CreateJobRequest":{"type":"object","properties":{"uploadKey":{"type":"string","description":"Key from POST /upload. Use this OR sourceUrl."},"sourceUrl":{"type":"string","description":"URL of audio file to process. Use this OR uploadKey."},"fileName":{"type":"string","description":"Original filename to store with the job (e.g. 'my-song.wav'). Overrides the default derived name. Useful when uploading via presigned URL where the original name is not preserved."},"outputType":{"type":"string","enum":["VOCALS","INSTRUMENTAL","BOTH","FOUR_STEMS","SIX_STEMS"],"default":"BOTH","description":"What stems to separate"},"quality":{"type":"string","enum":["FAST","BALANCED","BEST"],"default":"BEST","description":"Processing quality"},"outputFormat":{"type":"string","enum":["WAV","MP3","FLAC"],"default":"MP3","description":"Output file format"},"metadata":{"type":"object","description":"Custom metadata (returned in job response and webhooks)"},"denoiseVocals":{"type":"boolean","default":false,"description":"When true, applies noise removal to the vocal stem after separation."}}},"CreateSoundcloudJobRequest":{"type":"object","required":["soundcloudUrl"],"properties":{"soundcloudUrl":{"type":"string","description":"Public SoundCloud track URL. Accepted: soundcloud.com/artist/track, m.soundcloud.com/..., on.soundcloud.com/shortcode. Playlists and private tracks are not supported."},"outputDir":{"type":"string","description":"Output directory for MCP clients. Ignored by the REST API."}}},"CreateYoutubeJobRequest":{"type":"object","required":["youtubeUrl"],"properties":{"youtubeUrl":{"type":"string","description":"YouTube URL. Accepted formats: youtube.com/watch?v=ID, youtu.be/ID, youtube.com/embed/ID, or bare 11-character video ID."},"outputType":{"type":"string","enum":["VOCALS","INSTRUMENTAL","BOTH"],"default":"BOTH","description":"Output type. Fixed to vocals + instrumental for YouTube jobs (FOUR_STEMS and SIX_STEMS not supported)."},"quality":{"type":"string","enum":["FAST","BALANCED","BEST"],"default":"BEST"},"outputFormat":{"type":"string","enum":["MP3","WAV","FLAC"],"default":"MP3"}}},"JobCreatedResponse":{"type":"object","properties":{"id":{"type":"string","description":"Job ID"},"status":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","EXPIRED"]},"progress":{"type":"integer","description":"Progress percentage (0-100)"},"createdAt":{"type":"string","format":"date-time"},"estimatedSeconds":{"type":"integer","description":"Estimated processing time in seconds"},"creditsRequired":{"type":"integer","description":"Credits that will be charged (in seconds)"},"input":{"type":"object","properties":{"fileName":{"type":"string"},"durationSeconds":{"type":"integer"},"fileSizeBytes":{"type":"integer"}}},"options":{"type":"object","properties":{"outputType":{"type":"string"},"quality":{"type":"string"},"outputFormat":{"type":"string"}}},"outputs":{"type":"object","nullable":true},"metadata":{"type":"object","nullable":true}}},"JobDetailResponse":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","EXPIRED"]},"progress":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"startedAt":{"type":"string","format":"date-time","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"input":{"type":"object","properties":{"fileName":{"type":"string"},"durationSeconds":{"type":"integer"},"fileSizeBytes":{"type":"integer"}}},"options":{"type":"object","properties":{"outputType":{"type":"string"},"quality":{"type":"string"},"outputFormat":{"type":"string"}}},"audioMetadata":{"type":"object","nullable":true,"description":"Detected audio metadata (available when COMPLETED)","properties":{"bpm":{"type":"number","description":"Detected beats per minute"},"key":{"type":"string","description":"Detected musical key (e.g. 'Gm', 'C#')"}}},"outputs":{"type":"object","nullable":true,"description":"Download URLs for completed jobs","additionalProperties":{"type":"object","properties":{"url":{"type":"string","description":"Presigned download URL"},"expiresAt":{"type":"string","format":"date-time"}}}},"creditsCharged":{"type":"integer"},"errorMessage":{"type":"string","nullable":true},"expiresAt":{"type":"string","format":"date-time","nullable":true}}},"JobsListResponse":{"type":"object","properties":{"jobs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"progress":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time","nullable":true},"input":{"type":"object","properties":{"fileName":{"type":"string"},"durationSeconds":{"type":"integer"}}},"options":{"type":"object","properties":{"outputType":{"type":"string"},"quality":{"type":"string"},"outputFormat":{"type":"string"}}},"creditsCharged":{"type":"integer"},"errorMessage":{"type":"string","nullable":true}}}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}}}}},"SoundcloudJobCreatedResponse":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"soundcloudUrl":{"type":"string"},"trackTitle":{"type":"string","nullable":true},"trackDuration":{"type":"integer","nullable":true,"description":"Duration in seconds. May be null until fetched."},"creditsRequired":{"type":"integer","nullable":true,"description":"Credits required. May be null; 240 (4 min) is held until reconciled."},"createdAt":{"type":"string","format":"date-time"}}},"SoundcloudJobDetailResponse":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"soundcloudUrl":{"type":"string"},"trackTitle":{"type":"string","nullable":true},"trackDuration":{"type":"integer","nullable":true,"description":"Duration in seconds. May be null until fetched."},"creditsRequired":{"type":"integer","nullable":true,"description":"Credits required. May be null; 240 (4 min) is held until reconciled."},"createdAt":{"type":"string","format":"date-time"},"progress":{"type":"integer"},"audioMetadata":{"type":"object","nullable":true,"properties":{"bpm":{"type":"number"},"key":{"type":"string"}}},"completedAt":{"type":"string","format":"date-time","nullable":true},"outputs":{"type":"object","nullable":true,"properties":{"vocals":{"type":"object","properties":{"url":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}},"instrumental":{"type":"object","properties":{"url":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}}}},"creditsCharged":{"type":"integer","nullable":true},"errorMessage":{"type":"string","nullable":true}}},"SoundcloudJobsListResponse":{"type":"object","properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/SoundcloudJobDetailResponse"}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}}}}},"UploadRequest":{"type":"object","required":["filename"],"properties":{"filename":{"type":"string","description":"Name of the file to upload (e.g., 'song.mp3')"},"contentType":{"type":"string","description":"MIME type (auto-detected from filename if not provided)"}}},"UploadResponse":{"type":"object","properties":{"uploadUrl":{"type":"string","description":"Presigned URL - PUT your file here"},"uploadKey":{"type":"string","description":"Use this key when creating a job"},"expiresAt":{"type":"string","format":"date-time","description":"URL expiration time (15 minutes)"},"maxFileSizeBytes":{"type":"integer"},"maxFileSizeMb":{"type":"integer"},"contentType":{"type":"string"},"instructions":{"type":"object","properties":{"step1":{"type":"string"},"step2":{"type":"string"},"note":{"type":"string"}}}}},"BalanceResponse":{"type":"object","properties":{"balanceSeconds":{"type":"integer","description":"Balance in seconds"},"balanceMinutes":{"type":"integer","description":"Balance in whole minutes"},"balanceFormatted":{"type":"string","description":"Human-readable balance"},"updatedAt":{"type":"string","format":"date-time"}}},"CreateWebhookRequest":{"type":"object","required":["url"],"properties":{"url":{"type":"string","description":"URL to receive webhook notifications"},"events":{"type":"array","items":{"type":"string","enum":["job.completed","job.failed"]},"default":["job.completed","job.failed"],"description":"Events to subscribe to"}}},"WebhookCreatedResponse":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"secret":{"type":"string","description":"Signing secret - SAVE THIS, it's only shown once"},"isActive":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}}},"WebhooksListResponse":{"type":"object","properties":{"webhooks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string"},"events":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"failCount":{"type":"integer"},"lastError":{"type":"string","nullable":true},"lastCalledAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}}}}},"WebhookPayload":{"type":"object","description":"Payload sent to webhook endpoints","properties":{"event":{"type":"string","enum":["job.completed","job.failed"]},"timestamp":{"type":"string","format":"date-time"},"data":{"type":"object","properties":{"jobId":{"type":"string"},"status":{"type":"string"},"input":{"type":"object"},"options":{"type":"object"},"outputs":{"type":"object","nullable":true},"creditsCharged":{"type":"integer"},"errorMessage":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time","nullable":true}}}}},"YoutubeJobCreatedResponse":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"videoId":{"type":"string"},"videoTitle":{"type":"string"},"videoDuration":{"type":"integer","description":"Duration in seconds"},"videoThumbnail":{"type":"string"},"channelName":{"type":"string"},"creditsRequired":{"type":"integer"},"outputs":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"}}},"YoutubeJobDetailResponse":{"type":"object","properties":{"id":{"type":"string"},"status":{"type":"string"},"videoId":{"type":"string"},"videoTitle":{"type":"string"},"videoDuration":{"type":"integer","description":"Duration in seconds"},"videoThumbnail":{"type":"string"},"channelName":{"type":"string"},"creditsRequired":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"progress":{"type":"integer"},"audioMetadata":{"type":"object","nullable":true,"properties":{"bpm":{"type":"number"},"key":{"type":"string"}}},"completedAt":{"type":"string","format":"date-time","nullable":true},"outputs":{"type":"object","nullable":true,"additionalProperties":{"type":"object","properties":{"url":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"}}}},"creditsCharged":{"type":"integer"},"errorMessage":{"type":"string","nullable":true}}},"YoutubeJobsListResponse":{"type":"object","properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/YoutubeJobDetailResponse"}},"pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}}}}},"CreateDenoiseJobRequest":{"type":"object","required":["inputFileName","inputFilePath","inputFileSize","durationSeconds"],"properties":{"inputFileName":{"type":"string","description":"Original filename of the audio to denoise"},"inputFilePath":{"type":"string","description":"Upload key returned by POST /upload (uploadKey field)"},"inputFileSize":{"type":"integer","description":"File size in bytes"},"durationSeconds":{"type":"integer","description":"Duration of the audio file in seconds"},"outputFormat":{"type":"string","enum":["WAV","MP3","FLAC"],"default":"MP3","description":"Output file format"}}},"DenoiseJobResponse":{"type":"object","properties":{"id":{"type":"string","description":"Denoise job ID"},"jobId":{"type":"string","description":"Alias for id — returned on job creation"},"status":{"type":"string","enum":["PENDING","PROCESSING","COMPLETED","FAILED","EXPIRED"]},"progress":{"type":"integer","description":"Progress percentage (0-100)"},"inputFileName":{"type":"string","description":"Original filename"},"durationSeconds":{"type":"integer","description":"Audio duration in seconds"},"outputFormat":{"type":"string","enum":["WAV","MP3","FLAC"]},"outputFilePath":{"type":"string","nullable":true,"description":"Storage path of the denoised output (available when COMPLETED)"},"creditsCharged":{"type":"integer","nullable":true,"description":"Credits charged for the job (in seconds)"},"createdAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time","nullable":true},"errorMessage":{"type":"string","nullable":true}}}}}}