All notable changes to stemsplit-python are documented here. The format
is based on Keep a Changelog, and
this project adheres to Semantic Versioning.
0.1.0 - 2026-05-21 — Initial release: sync SDK for the StemSplit API
First public release. Synchronous Python client for the official StemSplit hosted stem-separation API.
StemSplitsync client (AsyncStemSplitplaceholder pointing at v0.2). Bearer-auth, env-var key default (STEMSPLIT_API_KEY), configurable base URL, softsk_live_prefix validation.- Resources for every public endpoint:
client.jobs— create (file / bytes / file-like /source_url/upload_key), get, list,iter_all, with the killer ergonomic layer:JobHandle.wait(),.iter_progress(),.refresh(),.download_all().client.youtube_jobs— create from YouTube URL, get, list,iter_all, samewait()/download_all()ergonomics. Surfaces video metadata (video_title,video_duration,channel_name,youtube_url) and the YouTube-specificfull_audiooutput.client.uploads— presigned-URL helpers (create_ticket,upload_bytes) for the rare case where you want to manage uploads yourself.client.account—balance()/get()returning typedBalance.client.webhooks—create,list,delete. Capturesecretfromcreate(); the API never returns it again.
- Webhook signature verification (
stemsplit_python.webhooks):verify_signaturefor raw-bytes verification andverify_and_parsethat returns a typedWebhookEvent. Constant-time HMAC-SHA256 comparison, accepts bothsha256=<hex>and bare hex. - Stripe-style error hierarchy mapping API responses 1:1 to typed
exceptions:
BadRequestError(400),AuthenticationError(401),InsufficientCreditsError(402, with.required_seconds/.purchase_url),PermissionDeniedError(403),NotFoundError(404),ConflictError(409),UnprocessableEntityError(422),RateLimitError(429, with.retry_after/.limit/.remaining/.reset_at),InternalServerError(5xx). Plus logical errorsJobFailedError,JobExpiredError,SignatureVerificationError. - Retries with backoff on
429and5xxfor safe-to-replay verbs (defaultmax_retries=3). HonorsRetry-Afterwhen present. - Rate-limit awareness: parses
X-RateLimit-*headers on every response, exposed asclient.last_rate_limit. - Idempotency-Key passthrough on
jobs.create,youtube_jobs.create,webhooks.create. Forwarded as a header today; lights up automatically when the API ships server-side support. - Audio metadata (BPM / key) on completed jobs:
Job.audio_metadataandYouTubeJob.audio_metadatatyped asAudioMetadata { bpm, key }. Both fields are optional and degrade gracefully if the analysis doesn't run. - Pydantic v2 models with
frozen=True,extra="allow"(forward- compatible against new server fields), snake_case Python attributes aliased to the camelCase wire fields, andLiteral[...]unions for every status / quality / format value (noenum.Enum). - Typing:
py.typedmarker shipped,mypy --strictclean. - Three runtime dependencies only:
httpx,pydantic,typing-extensions(Python 3.10 backport only). No PyTorch, no numpy, no native code. - Snapshot of the live OpenAPI 3.1 spec at
openapi/openapi.jsonso future versions can diff API drift.
- 62 tests, ~92 % line coverage, all
respx-backed mocks. Full status- code → exception matrix, retry behavior, end-to-endjobs.create(audio=Path)chain,wait()happy / failed / timeout paths, webhook signature round-trip + tamper detection, and YouTube job lifecycle.
AsyncStemSplit— lands in v0.2. Constructing it today raisesNotImplementedErrorwith a pointer at the tracking issue.job.cancel()— the API does not yet exposeDELETE /jobs/{id}; honest omission rather than a no-op stub. Will land alongside the endpoint.- CLI — a separate
stemsplit-cliadd-on is planned for v0.2 so the SDK stays dependency-light.